[Cluster-devel] cluster/gfs2 edit/Makefile edit/gfs2hex.c edit ...

rpeterso at sourceware.org rpeterso at sourceware.org
Tue Jun 26 01:40:44 UTC 2007


CVSROOT:	/cvs/cluster
Module name:	cluster
Branch: 	RHEL5
Changes by:	rpeterso at sourceware.org	2007-06-26 01:40:43

Modified files:
	gfs2/edit      : Makefile gfs2hex.c hexedit.c hexedit.h 
	gfs2/libgfs2   : super.c 

Log message:
	Resolves: bz 245635: Bring gfs2_edit up to date

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/Makefile.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4&r2=1.4.2.1
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/gfs2hex.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.5.2.2&r2=1.5.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.6.2.2&r2=1.6.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/edit/hexedit.h.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.4.2.2&r2=1.4.2.3
http://sourceware.org/cgi-bin/cvsweb.cgi/cluster/gfs2/libgfs2/super.c.diff?cvsroot=cluster&only_with_tag=RHEL5&r1=1.3.2.1&r2=1.3.2.2

--- cluster/gfs2/edit/Makefile	2006/08/11 15:18:12	1.4
+++ cluster/gfs2/edit/Makefile	2007/06/26 01:40:43	1.4.2.1
@@ -15,6 +15,7 @@
 
 SOURCE=	\
 	gfs2hex.c \
+	savemeta.c \
 	hexedit.c
 
 top_srcdir=..
--- cluster/gfs2/edit/gfs2hex.c	2006/11/14 20:13:36	1.5.2.2
+++ cluster/gfs2/edit/gfs2hex.c	2007/06/26 01:40:43	1.5.2.3
@@ -41,12 +41,12 @@
 extern uint64_t bufsize;
 extern int line, termlines;
 extern char edit_fmt[80];
-extern char edit_string[1024];
+extern char estring[1024];
 extern int edit_mode INIT(0);
-extern int edit_row[DISPLAY_MODES], edit_col[DISPLAY_MODES];
-extern int edit_size[DISPLAY_MODES], edit_last[DISPLAY_MODES];
-extern char edit_string[1024], edit_fmt[80];
-extern enum dsp_mode display_mode INIT(HEX_MODE);
+extern int edit_row[DMODES], edit_col[DMODES];
+extern int edit_size[DMODES], last_entry_onscreen[DMODES];
+extern char edit_fmt[80];
+extern enum dsp_mode dmode INIT(HEX_MODE); /* display mode */
 
 void eol(int col) /* end of line */
 {
@@ -76,6 +76,33 @@
 	va_end(args);
 }
 
+void check_highlight(int highlight)
+{
+	if (!termlines || line >= termlines) /* If printing or out of bounds */
+		return;
+	if (dmode == HEX_MODE) {
+		if (line == (edit_row[dmode] * lines_per_row[dmode]) + 4) {
+			if (highlight) {
+				COLORS_HIGHLIGHT;
+				last_entry_onscreen[dmode] = print_entry_ndx;
+			}
+			else
+				COLORS_NORMAL;
+		}
+	}
+	else {
+		if ((line * lines_per_row[dmode]) - 4 == 
+			(edit_row[dmode] - start_row[dmode]) * lines_per_row[dmode]) {
+			if (highlight) {
+				COLORS_HIGHLIGHT;
+				last_entry_onscreen[dmode] = print_entry_ndx;
+			}
+			else
+				COLORS_NORMAL;
+		}
+	}
+}
+
 void print_it(const char *label, const char *fmt, const char *fmt2, ...)
 {
 	va_list args;
@@ -85,13 +112,10 @@
 
 	if (!termlines || line < termlines) {
 		va_start(args, fmt2);
+		check_highlight(TRUE);
 		if (termlines) {
-			if (line == edit_row[display_mode] + 4)
-				COLORS_HIGHLIGHT;
 			move(line,0);
 			printw("%s", label);
-			if (line == edit_row[display_mode] + 4)
-				COLORS_NORMAL;
 			move(line,24);
 		}
 		else {
@@ -102,28 +126,21 @@
 		}
 		vsprintf(tmp_string, fmt, args);
 
-		if (termlines) {
-			if (line == edit_row[display_mode] + 4)
-				COLORS_HIGHLIGHT;
+		if (termlines)
 			printw(tmp_string);
-			if (line == edit_row[display_mode] + 4)
-				COLORS_NORMAL;
-		}
 		else
 			printf(tmp_string);
+		check_highlight(FALSE);
 
 		if (fmt2) {
 			decimalsize = strlen(tmp_string);
 			va_end(args);
 			va_start(args, fmt2);
 			vsprintf(tmp_string, fmt2, args);
+			check_highlight(TRUE);
 			if (termlines) {
 				move(line, 50);
-				if (line == edit_row[display_mode] + 4)
-					COLORS_HIGHLIGHT;
 				printw("%s", tmp_string);
-				if (line == edit_row[display_mode] + 4)
-					COLORS_NORMAL;
 			}
 			else {
 				int i;
@@ -131,6 +148,7 @@
 					printf(" ");
 				printf("%s", tmp_string);
 			}
+			check_highlight(FALSE);
 		}
 		else {
 			if (strstr(fmt,"X") || strstr(fmt,"x"))
@@ -148,14 +166,13 @@
 		}
 		if (termlines) {
 			refresh();
-			if (line == edit_row[display_mode] + 4) {
-				strcpy(edit_string, tmp_string);
+			if (line == (edit_row[dmode] * lines_per_row[dmode]) + 4) {
+				strcpy(estring, tmp_string);
 				strcpy(edit_fmt, fmt);
-				edit_size[display_mode] = strlen(edit_string);
+				edit_size[dmode] = strlen(estring);
 				COLORS_NORMAL;
 			}
-			if (line - 3 > edit_last[display_mode])
-				edit_last[display_mode] = line - 4;
+			last_entry_onscreen[dmode] = (line / lines_per_row[dmode]) - 4;
 		}
 		eol(0);
 		va_end(args);
@@ -293,7 +310,8 @@
 
 	indirect_blocks = 0;
 	memset(&indirect, 0, sizeof(indirect));
-	for (x = sizeof(struct gfs_indirect), y = 0;
+	for (x = (gfs1 ? sizeof(struct gfs_indirect):
+			  sizeof(struct gfs2_meta_header)), y = 0;
 		 x < bufsize;
 		 x += sizeof(uint64_t), y++) {
 		p = be64_to_cpu(*(uint64_t *)(buf + x));
@@ -326,7 +344,7 @@
 	unsigned int x;
 
 	eol(0);
-	printf("Directory Entries:");
+	print_gfs2("Directory Entries:");
 	eol(0);
 
 	for (x = sizeof(struct gfs2_leaf); x < bufsize; x += de.de_rec_len) {
@@ -360,7 +378,7 @@
 	unsigned int x;
 
 	eol(0);
-	printf("Eattr Entries:");
+	print_gfs2("Eattr Entries:");
 	eol(0);
 
 	for (x = sizeof(struct gfs2_meta_header); x < bufsize; x += ea.ea_rec_len)
@@ -374,8 +392,10 @@
 void gfs2_inum_print2(const char *title,struct gfs2_inum *no)
 {
 	if (termlines) {
+		check_highlight(TRUE);
 		move(line,2);
 		printw(title);
+		check_highlight(FALSE);
 	}
 	else
 		printf("  %s:",title);
--- cluster/gfs2/edit/hexedit.c	2006/11/14 20:13:36	1.6.2.2
+++ cluster/gfs2/edit/hexedit.c	2007/06/26 01:40:43	1.6.2.3
@@ -42,9 +42,13 @@
 
 #include <syslog.h>
 
-int display(enum dsp_mode display_mode, int identify_only);
+#define RGLIST_DUMMY_BLOCK -2
+
+int display(int identify_only);
 extern void eol(int col);
 extern void do_indirect_extended(char *buf);
+extern void savemeta(const char *in_fn, const char *out_fn, int slow);
+extern void restoremeta(const char *in_fn, const char *out_device);
 
 /* ------------------------------------------------------------------------ */
 /* UpdateSize - screen size changed, so update it                           */
@@ -70,7 +74,7 @@
 	else
 		perror("Error: tgetent failed.");
 	termlines--; /* last line is number of lines -1 */
-	display(display_mode, FALSE);
+	display(FALSE);
 	signal(SIGWINCH, UpdateSize);
 }
 
@@ -112,9 +116,9 @@
 /* returns: 1 if user exited by hitting enter                                */
 /*          0 if user exited by hitting escape                               */
 /* ------------------------------------------------------------------------- */
-int bobgets(char string[],int x,int y,int sz)
+int bobgets(char string[],int x,int y,int sz,int *ch)
 {
-	int done,ch,runningy,rc;
+	int done,runningy,rc;
 
 	move(x,y);
 	done=FALSE;
@@ -127,23 +131,29 @@
 	runningy=y;
 	rc=0;
 	while (!done) {
-		ch=getch();
+		*ch = getch();
 		
-		if(ch < 0x0100 && isprint(ch)) {
+		if(*ch < 0x0100 && isprint(*ch)) {
 			char *p=string+strlen(string); // end of the string
+
 			*(p+1)='\0';
 			while (insert && p > &string[runningy-y]) {
 				*p=*(p-1);
 				p--;
 			}
-			string[runningy-y]=ch;
+			string[runningy-y]=*ch;
 			runningy++;
 			move(x,y);
 			addstr(string);
+			if (runningy-y >= sz) {
+				rc=1;
+				*ch = KEY_RIGHT;
+				done = TRUE;
+			}
 		}
 		else {
 			// special character, is it one we recognize?
-			switch(ch)
+			switch(*ch)
 			{
 			case(KEY_ENTER):
 			case('\n'):
@@ -157,11 +167,20 @@
 				done=TRUE;
 				break;
 			case(KEY_LEFT):
-				if (runningy>y)
+				if (dmode == HEX_MODE) {
+					done = TRUE;
+					rc = 1;
+				}
+				else
 					runningy--;
 				break;
 			case(KEY_RIGHT):
-				runningy++;
+				if (dmode == HEX_MODE) {
+					done = TRUE;
+					rc = 1;
+				}
+				else
+					runningy++;
 				break;
 			case(KEY_DC):
 			case(0x07F):
@@ -220,7 +239,7 @@
 				break;
 			default:
 				move(0,70);
-				printw("%08X",ch);
+				printw("%08X",*ch);
 				// ignore all other characters
 				break;
 			} // end switch on non-printable character
@@ -323,12 +342,15 @@
 	}
 	print_gfs2("Block #");
 	if (termlines) {
-		if (edit_row[display_mode] == -1)
+		if (edit_row[dmode] == -1)
 			COLORS_HIGHLIGHT;
 	}
-	print_gfs2("%lld    (0x%"PRIx64")", block, block);
+	if (block == RGLIST_DUMMY_BLOCK)
+		print_gfs2("RG List       ");
+	else
+		print_gfs2("%lld    (0x%"PRIx64")", block, block);
 	if (termlines) {
-		if (edit_row[display_mode] == -1)
+		if (edit_row[dmode] == -1)
 			COLORS_NORMAL;
 		move(line,30);
 	}
@@ -340,9 +362,14 @@
 	else
 		printf(" ");
 
-	if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 && *(lpBuffer+2)==0x19 &&
-		*(lpBuffer+3)==0x70 && *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 &&
-		*(lpBuffer+6)==0x00) { /* If magic number appears at the start */
+	if (block == RGLIST_DUMMY_BLOCK) {
+		ret_type = GFS2_METATYPE_RG;
+		struct_len = sizeof(struct gfs2_rgrp);
+	}
+	else if (*(lpBuffer+0)==0x01 && *(lpBuffer+1)==0x16 &&
+	    *(lpBuffer+2)==0x19 && *(lpBuffer+3)==0x70 &&
+	    *(lpBuffer+4)==0x00 && *(lpBuffer+5)==0x00 &&
+	    *(lpBuffer+6)==0x00) { /* If magic number appears at the start */
 		ret_type = *(lpBuffer+7);
 		switch (*(lpBuffer+7)) {
 		case GFS2_METATYPE_SB:   /* 1 */
@@ -401,7 +428,7 @@
 	else
 		struct_len = 512;
 	eol(0);
-	if (termlines && display_mode == HEX_MODE) {
+	if (termlines && dmode == HEX_MODE) {
 		/* calculate how much of the buffer we can fit on screen */
 		screen_chunk_size = ((termlines - 4) * 16) >> 8 << 8;
 		if (!screen_chunk_size)
@@ -413,9 +440,11 @@
 		/*eol(9);*/
 	}
 	if (block == sbd.sd_sb.sb_root_dir.no_addr)
-		print_gfs2("-------------------- Root direcory -------------------");
+		print_gfs2("-------------------- Root directory ------------------");
 	else if (!gfs1 && block == sbd.sd_sb.sb_master_dir.no_addr)
 		print_gfs2("------------------- Master directory -----------------");
+	else if (!gfs1 && block == RGLIST_DUMMY_BLOCK)
+		print_gfs2("----------------------- RG List ----------------------");
 	else {
 		if (gfs1) {
 			if (block == sbd1->sb_rindex_di.no_addr)
@@ -465,6 +494,7 @@
 	pointer = (unsigned char *)lpBuffer + offset;
 	ptr2 = (unsigned char *)lpBuffer + offset;
 	l = offset;
+	print_entry_ndx = 0;
 	while (((termlines &&
 			line < termlines &&
 			line <= ((screen_chunk_size / 16) + 2)) ||
@@ -499,15 +529,15 @@
 			}
 			if (i%4 == 0)
 				print_gfs2(" ");
-			if (termlines && line == edit_row[display_mode] + 3 &&
-				i == edit_col[display_mode]) {
+			if (termlines && line == edit_row[dmode] + 3 &&
+				i == edit_col[dmode]) {
 				COLORS_HIGHLIGHT; /* normal part of the structure */
-				memset(edit_string,0,3);
-				sprintf(edit_string,"%02X",*pointer);
+				memset(estring,0,3);
+				sprintf(estring,"%02X",*pointer);
 			}
 			print_gfs2("%02X",*pointer);
-			if (termlines && line == edit_row[display_mode] + 3 &&
-				i == edit_col[display_mode]) {
+			if (termlines && line == edit_row[dmode] + 3 &&
+				i == edit_col[dmode]) {
 				if (l < struct_len + offset)
 					COLORS_NORMAL; /* normal part of the structure */
 				else
@@ -524,10 +554,11 @@
 			ptr2++;
 		}
 		print_gfs2("] ");
-		if (line - 3 > edit_last[display_mode])
-			edit_last[display_mode] = line - 3;
+		if (line - 3 > last_entry_onscreen[dmode])
+			last_entry_onscreen[dmode] = line - 3;
 		eol(0);
 		l+=16;
+		print_entry_ndx++;
 	} /* while */
 	if (gfs1) {
 		COLORS_NORMAL;
@@ -552,28 +583,125 @@
 }
 
 /* ------------------------------------------------------------------------ */
-/* print_rindex - print the rgindex file.                                   */
+/* parse_rindex - print the rgindex file.                                   */
 /* ------------------------------------------------------------------------ */
-int print_rindex(struct gfs2_inode *di)
+int parse_rindex(struct gfs2_inode *di, int print_rindex)
 {
-	int rgs, error;
+	int error, start_line;
 	struct gfs2_rindex ri;
 	char buf[sizeof(struct gfs2_rindex)];
+	char highlighted_addr[32];
 
+	start_line = line;
 	error = 0;
 	print_gfs2("RG index entries found: %d.",
 			   di->i_di.di_size / sizeof(struct gfs2_rindex));
 	eol(0);
-	for (rgs=0; ; rgs++) {
-		error = gfs2_readi(di, (void *)&buf, rgs * sizeof(struct gfs2_rindex),
-						   sizeof(struct gfs2_rindex));
+	lines_per_row[dmode] = 6;
+	memset(highlighted_addr, 0, sizeof(highlighted_addr));
+	for (print_entry_ndx=0; ; print_entry_ndx++) {
+		error = gfs2_readi(di, (void *)&buf,
+				   print_entry_ndx * sizeof(struct gfs2_rindex),
+				   sizeof(struct gfs2_rindex));
 		gfs2_rindex_in(&ri, buf);
 		if (!error) /* end of file */
 			break;
-		print_gfs2("RG #%d", rgs + 1);
-		eol(0);
-		gfs2_rindex_print(&ri);
+		if (!termlines ||
+			(print_entry_ndx >= start_row[dmode] &&
+			 ((print_entry_ndx - start_row[dmode])+1) * lines_per_row[dmode] <=
+			 termlines - start_line - 2)) {
+			if (edit_row[dmode] == print_entry_ndx) {
+				COLORS_HIGHLIGHT;
+				sprintf(highlighted_addr, "%llx", (unsigned long long)ri.ri_addr);
+			}
+			print_gfs2("RG #%d", print_entry_ndx);
+			if (!print_rindex)
+				print_gfs2(" located at: %llu (0x%llx)",
+					   ri.ri_addr, ri.ri_addr);
+			eol(0);
+			if (edit_row[dmode] == print_entry_ndx)
+				COLORS_NORMAL;
+			if(print_rindex)
+				gfs2_rindex_print(&ri);
+			else {
+				struct gfs2_rgrp rg;
+				struct gfs2_buffer_head *tmp_bh;
+
+				tmp_bh = bread(&sbd, ri.ri_addr);
+				gfs2_rgrp_in(&rg, tmp_bh->b_data);
+				gfs2_rgrp_print(&rg);
+				brelse(tmp_bh, not_updated);
+			}
+			last_entry_onscreen[dmode] = print_entry_ndx;
+		}
+	}
+	strcpy(estring, highlighted_addr);
+	end_row[dmode] = print_entry_ndx;
+	return error;
+}
+
+/* ------------------------------------------------------------------------ */
+/* gfs_jindex_in - read in a gfs1 jindex structure.                         */
+/* ------------------------------------------------------------------------ */
+void gfs_jindex_in(struct gfs_jindex *jindex, char *buf)
+{
+        struct gfs_jindex *str = (struct gfs_jindex *) buf;
+
+        jindex->ji_addr = be64_to_cpu(str->ji_addr);
+        jindex->ji_nsegment = be32_to_cpu(str->ji_nsegment);
+        jindex->ji_pad = be32_to_cpu(str->ji_pad);
+        memcpy(jindex->ji_reserved, str->ji_reserved, 64);
+}
+
+/* ------------------------------------------------------------------------ */
+/* gfs_jindex_print - print an jindex entry.                                */
+/* ------------------------------------------------------------------------ */
+void gfs_jindex_print(struct gfs_jindex *ji)
+{
+        pv(ji, ji_addr, "%llu", "0x%llx");
+        pv(ji, ji_nsegment, "%u", "0x%x");
+        pv(ji, ji_pad, "%u", "0x%x");
+}
+
+/* ------------------------------------------------------------------------ */
+/* print_jindex - print the jindex file.                                    */
+/* ------------------------------------------------------------------------ */
+int print_jindex(struct gfs2_inode *di)
+{
+	int error, start_line;
+	struct gfs_jindex ji;
+	char buf[sizeof(struct gfs_jindex)];
+
+	start_line = line;
+	error = 0;
+	print_gfs2("Journal index entries found: %d.",
+		   di->i_di.di_size / sizeof(struct gfs_jindex));
+	eol(0);
+	lines_per_row[dmode] = 6;
+	for (print_entry_ndx=0; ; print_entry_ndx++) {
+		error = gfs2_readi(di, (void *)&buf,
+				   print_entry_ndx*sizeof(struct gfs_jindex),
+				   sizeof(struct gfs_jindex));
+		gfs_jindex_in(&ji, buf);
+		if (!error) /* end of file */
+			break;
+		if (!termlines ||
+		    (print_entry_ndx >= start_row[dmode] &&
+		     ((print_entry_ndx - start_row[dmode])+1) *
+		     lines_per_row[dmode] <= termlines - start_line - 2)) {
+			if (edit_row[dmode] == print_entry_ndx) {
+				COLORS_HIGHLIGHT;
+				sprintf(estring, "%" PRIx64, ji.ji_addr);
+			}
+			print_gfs2("Journal #%d", print_entry_ndx);
+			eol(0);
+			if (edit_row[dmode] == print_entry_ndx)
+				COLORS_NORMAL;
+			gfs_jindex_print(&ji);
+			last_entry_onscreen[dmode] = print_entry_ndx;
+		}
 	}
+	end_row[dmode] = print_entry_ndx;
 	return error;
 }
 
@@ -644,168 +772,358 @@
 }
 
 /* ------------------------------------------------------------------------ */
-/* display_extended                                                         */
+/* has_indirect_blocks                                                      */
 /* ------------------------------------------------------------------------ */
-int display_extended(void)
+int has_indirect_blocks(void)
 {
-	int e, start_line, total_dirents, indir_blocks;
-	struct gfs2_inode *tmp_inode;
+	if (indirect_blocks || gfs2_struct_type == GFS2_METATYPE_SB ||
+		(gfs2_struct_type == GFS2_METATYPE_DI &&
+		 (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR))))
+		return TRUE;
+	return FALSE;
+}
 
-	edit_last[display_mode] = 0;
+/* ------------------------------------------------------------------------ */
+/* print_inode_type                                                         */
+/* ------------------------------------------------------------------------ */
+void print_inode_type(__be16 de_type)
+{
+	switch(de_type) {
+	case DT_UNKNOWN:
+		print_gfs2("Unknown");
+		break;
+	case DT_REG:
+		print_gfs2("File   ");
+		break;
+	case DT_DIR:
+		print_gfs2("Dir    ");
+		break;
+	case DT_LNK:
+		print_gfs2("Symlink");
+		break;
+	case DT_BLK:
+		print_gfs2("BlkDev ");
+		break;
+	case DT_CHR:
+		print_gfs2("ChrDev ");
+		break;
+	case DT_FIFO:
+		print_gfs2("Fifo   ");
+		break;
+	case DT_SOCK:
+		print_gfs2("Socket ");
+		break;
+	default:
+		print_gfs2("%04x   ", de_type);
+		break;
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* display_indirect                                                         */
+/* ------------------------------------------------------------------------ */
+int display_indirect(void)
+{
+	int start_line, total_dirents, indir_blocks;
+	int i, cur_height = -1;
+	uint64_t factor[5]={0,0,0,0,0};
+	int offsets[5];
+
+	last_entry_onscreen[dmode] = 0;
 	eol(0);
 	start_line = line;
-	if (indirect_blocks ||
-		(gfs2_struct_type == GFS2_METATYPE_DI &&
-		 (S_ISDIR(di.di_mode) || (gfs1 && di.__pad1 == GFS_FILE_DIR)))) {
-		indir_blocks = indirect_blocks;
-		if (!indirect_blocks) {
+	if (!has_indirect_blocks())
+		return -1;
+
+	indir_blocks = indirect_blocks;
+	if (!indirect_blocks) {
+		if (gfs2_struct_type == GFS2_METATYPE_SB)
+			print_gfs2("The superblock has 2 directories");
+		else
 			print_gfs2("This directory contains %d directory entries.",
 					   indirect[0].dirents);
-			eol(0);
-			indir_blocks = 1; /* not really an indirect block, but treat it as one */
-		}
-		else {
-			if (gfs2_struct_type == GFS2_METATYPE_DI && S_ISDIR(di.di_mode))
+		indir_blocks = 1; /* not really an indirect block, but treat it as one */
+	}
+	else {
+		if (gfs2_struct_type == GFS2_METATYPE_DI) {
+			if (S_ISDIR(di.di_mode))
 				print_gfs2("This directory contains %d indirect blocks",
 						   indirect_blocks);
 			else
 				print_gfs2("This inode contains %d indirect blocks",
 						   indirect_blocks);
-			eol(0);
-			print_gfs2("Indirect blocks for this inode:");
-			eol(0);
 		}
-		total_dirents = 0;
-		for (e = 0; (!termlines || e < termlines - start_line - 2) &&
-				 e < indir_blocks; e++) {
+		else
+			print_gfs2("This indirect block contains %d indirect blocks",
+					   indirect_blocks);
+	}
+	total_dirents = 0;
+	/* Figure out multiplication factors for indirect pointers. */
+	if ((indir_blocks == indirect_blocks) && !S_ISDIR(di.di_mode)) {
+		memset(&offsets, 0, sizeof(offsets));
+		/* See if we are on an inode or have one in history. */
+		cur_height = 0;
+		if (gfs2_struct_type != GFS2_METATYPE_DI) {
+			cur_height = 0;
+			for (i = 0; i <= blockhist && i < 5; i++) {
+				offsets[i] = blockstack[(blockhist - i) % BLOCK_STACK_SIZE].edit_row[dmode];
+				if (blockstack[(blockhist - i) % BLOCK_STACK_SIZE].gfs2_struct_type == GFS2_METATYPE_DI)
+					break;
+				cur_height++;
+			}
+		}
+		if (cur_height >= 0) {
+			int diptrs, inptrs;
+
+			if (gfs1) {
+				diptrs = 483;
+				inptrs = 501;
+			} else {
+				diptrs = (bufsize - sizeof(sizeof(struct gfs2_dinode))) / sizeof(uint64_t);
+				inptrs = (bufsize - sizeof(sizeof(struct gfs2_meta_header))) /
+					sizeof(uint64_t);
+			}
+			/* Multiply out the max factor based on inode height.*/
+			/* This is how much data is represented by each      */
+			/* indirect pointer at each height.                  */
+			factor[0] = 1ull;
+			for (i = 0; i < di.di_height; i++)
+				factor[i + 1] = factor[i] * inptrs;
+		}
+		print_gfs2("  (at height=%d)", cur_height);
+	}
+	if (indirect_blocks) {
+		eol(0);
+		print_gfs2("Indirect blocks:");
+	}
+	eol(0);
+	for (print_entry_ndx = start_row[dmode];
+		 (!termlines || print_entry_ndx < termlines - start_line - 2
+		  + start_row[dmode]) && print_entry_ndx < indir_blocks;
+		 print_entry_ndx++) {
+		if (termlines) {
+			if (edit_row[dmode] >= 0 &&
+				line - start_line - 2 == edit_row[dmode] -
+				start_row[dmode])
+				COLORS_HIGHLIGHT;
+			move(line, 1);
+		}
+		if (indir_blocks == indirect_blocks) {
+			print_gfs2("%d => ", print_entry_ndx);
+			if (termlines)
+				move(line,9);
+			print_gfs2("0x%llx / %lld", indirect[print_entry_ndx].block,
+					   indirect[print_entry_ndx].block);
 			if (termlines) {
-				if (edit_row[display_mode] >= 0 &&
-					line - start_line - 2 == edit_row[display_mode])
-					COLORS_HIGHLIGHT;
-				move(line, 1);
-			}
-			if (indir_blocks == indirect_blocks) {
-				print_gfs2("%d => ", e);
-				if (termlines)
-					move(line,9);
-				print_gfs2("0x%llx / %lld", indirect[e].block,
-						   indirect[e].block);
-				if (termlines) {
-					if (edit_row[display_mode] >= 0 &&
-						line - start_line - 2 == edit_row[display_mode]) { 
-						sprintf(edit_string, "%"PRIx64, indirect[e].block);
-						strcpy(edit_fmt, "%"PRIx64);
-						edit_size[display_mode] = strlen(edit_string);
-						COLORS_NORMAL;
-					}
+				if (edit_row[dmode] >= 0 &&
+					line - start_line - 2 == edit_row[dmode] -
+					start_row[dmode]) { 
+					sprintf(estring, "%"PRIx64,
+							indirect[print_entry_ndx].block);
+					strcpy(edit_fmt, "%"PRIx64);
+					edit_size[dmode] = strlen(estring);
+					COLORS_NORMAL;
 				}
 			}
-			if (indir_blocks == indirect_blocks)
+			if (!S_ISDIR(di.di_mode)) {
+				int hgt;
+				uint64_t file_offset = 0ull;
+				float human_off;
+				char h;
+				
+				/* Now divide by how deep we are at the moment.      */
+				/* This is how much data is represented by each      */
+				/* indirect pointer for each height we've traversed. */
+				offsets[0] = print_entry_ndx;
+				for (hgt = cur_height; hgt >= 0; hgt--)
+					file_offset += offsets[cur_height - hgt] *
+						factor[di.di_height - hgt - 1] * bufsize;
+				print_gfs2("     ");
+				h = 'K';
+				human_off = (file_offset / 1024.0);
+				if (human_off > 1024.0) { h = 'M'; human_off /= 1024.0; }
+				if (human_off > 1024.0) { h = 'G'; human_off /= 1024.0; }
+				if (human_off > 1024.0) { h = 'T'; human_off /= 1024.0; }
+				if (human_off > 1024.0) { h = 'P'; human_off /= 1024.0; }
+				if (human_off > 1024.0) { h = 'E'; human_off /= 1024.0; }
+				print_gfs2("(data offset 0x%llx / %lld / %6.2f%c)",
+						   file_offset, file_offset, human_off, h);
 				print_gfs2("   ");
-			if (indirect[e].is_dir) {
-				int d;
-
-				if (indirect[e].dirents > 1 && indir_blocks == indirect_blocks)
-					print_gfs2("(directory leaf with %d entries)",
-							   indirect[e].dirents);
-				for (d = 0; d < indirect[e].dirents; d++) {
-					total_dirents++;
-					if (indirect[e].dirents > 1) {
-						eol(5);
-						if (termlines) {
-							if (edit_row[display_mode] >=0 &&
-								line - start_line - 2 == edit_row[display_mode]) {
-								COLORS_HIGHLIGHT;
-								sprintf(edit_string, "%"PRIx64,
-										indirect[e].dirent[d].block);
-								strcpy(edit_fmt, "%"PRIx64);
-							}
-						}
-						print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ",
-								   total_dirents, d + 1,
-								   indirect[e].dirent[d].dirent.de_inum.no_formal_ino,
-								   indirect[e].dirent[d].dirent.de_inum.no_formal_ino,
-								   indirect[e].dirent[d].block,
-								   indirect[e].dirent[d].block);
-					}
-					switch(indirect[e].dirent[d].dirent.de_type) {
-					case DT_UNKNOWN:
-						print_gfs2("Unknown");
-						break;
-					case DT_REG:
-						print_gfs2("File   ");
-						break;
-					case DT_DIR:
-						print_gfs2("Dir    ");
-						break;
-					case DT_LNK:
-						print_gfs2("Symlink");
-						break;
-					case DT_BLK:
-						print_gfs2("BlkDev ");
-						break;
-					case DT_CHR:
-						print_gfs2("ChrDev ");
-						break;
-					case DT_FIFO:
-						print_gfs2("Fifo   ");
-						break;
-					case DT_SOCK:
-						print_gfs2("Socket ");
-						break;
-					default:
-						print_gfs2("%04x   ",
-								   indirect[e].dirent[d].dirent.de_type);
-						break;
-					}
-
-					print_gfs2(" %s", indirect[e].dirent[d].filename);
+			}
+		}
+		if (indirect[print_entry_ndx].is_dir) {
+			int d;
+			
+			if (indirect[print_entry_ndx].dirents > 1 &&
+				indir_blocks == indirect_blocks)
+				print_gfs2("(directory leaf with %d entries)",
+						   indirect[print_entry_ndx].dirents);
+			for (d = 0; d < indirect[print_entry_ndx].dirents; d++) {
+				total_dirents++;
+				if (indirect[print_entry_ndx].dirents > 1) {
+					eol(5);
 					if (termlines) {
-						if (edit_row[display_mode] >= 0 &&
-							line - start_line - 2 == edit_row[display_mode])
-							COLORS_NORMAL;
+						if (edit_row[dmode] >=0 &&
+							line - start_line - 2 == 
+							edit_row[dmode] -
+							start_row[dmode]) {
+							COLORS_HIGHLIGHT;
+							sprintf(estring, "%"PRIx64,
+									indirect[print_entry_ndx].dirent[d].block);
+							strcpy(edit_fmt, "%"PRIx64);
+						}
 					}
+					print_gfs2("%d. (%d). %lld (0x%llx) / %lld (0x%llx): ",
+							   total_dirents, d + 1,
+							   indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino,
+							   indirect[print_entry_ndx].dirent[d].dirent.de_inum.no_formal_ino,
+							   indirect[print_entry_ndx].dirent[d].block,
+							   indirect[print_entry_ndx].dirent[d].block);
 				}
-			} /* if isdir */
-			else
-				print_gfs2("indirect block");
-			eol(0);
-		} /* for termlines */
-		if (line >= 7) /* 7 because it was bumped at the end */
-			edit_last[display_mode] = line - 7;
-	} /* if (indirect_blocks) */
-	else
-		print_gfs2("This block does not have indirect blocks.");
+				print_inode_type(indirect[print_entry_ndx].dirent[d].dirent.de_type);
+				print_gfs2(" %s", indirect[print_entry_ndx].dirent[d].filename);
+				if (termlines) {
+					if (edit_row[dmode] >= 0 &&
+						line - start_line - 2 == edit_row[dmode] -
+						start_row[dmode])
+						COLORS_NORMAL;
+				}
+			}
+		} /* if isdir */
+		eol(0);
+	} /* for each display row */
+	if (line >= 7) /* 7 because it was bumped at the end */
+		last_entry_onscreen[dmode] = line - 7;
 	eol(0);
+	end_row[dmode] = (indirect_blocks ? indirect_blocks:indirect[0].dirents);
+	if (end_row[dmode] < last_entry_onscreen[dmode])
+		end_row[dmode] = last_entry_onscreen[dmode];
+	lines_per_row[dmode] = 1;
+	return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_rindex                                                          */
+/* ------------------------------------------------------------------------ */
+int block_is_rindex(void)
+{
 	if ((gfs1 && block == sbd1->sb_rindex_di.no_addr) ||
-		(block == masterblock("rindex"))) {
-		struct gfs2_buffer_head *tmp_bh;
+	    (block == masterblock("rindex")))
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_rglist - there's no such block as the rglist.  This is a        */
+/*                   special case meant to parse the rindex and follow the  */
+/*                   blocks to the real rgs.                                */
+/* ------------------------------------------------------------------------ */
+int block_is_rglist(void)
+{
+	if (block == RGLIST_DUMMY_BLOCK)
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_jindex                                                          */
+/* ------------------------------------------------------------------------ */
+int block_is_jindex(void)
+{
+	if ((gfs1 && block == sbd1->sb_jindex_di.no_addr))
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_inum_file                                                       */
+/* ------------------------------------------------------------------------ */
+int block_is_inum_file(void)
+{
+	if (!gfs1 && block == masterblock("inum"))
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_statfs_file                                                     */
+/* ------------------------------------------------------------------------ */
+int block_is_statfs_file(void)
+{
+	if (!gfs1 && block == masterblock("statfs"))
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_is_quota_file                                                      */
+/* ------------------------------------------------------------------------ */
+int block_is_quota_file(void)
+{
+	if ((gfs1 && block == gfs1_quota_di.no_addr) ||
+	    (block == masterblock("quota")))
+		return TRUE;
+	return FALSE;
+}
+
+/* ------------------------------------------------------------------------ */
+/* block_has_extended_info                                                  */
+/* ------------------------------------------------------------------------ */
+int block_has_extended_info(void)
+{
+	if (has_indirect_blocks() ||
+	    block_is_rindex() ||
+	    block_is_rglist() ||
+	    block_is_jindex() ||
+	    block_is_inum_file() ||
+	    block_is_statfs_file() ||
+	    block_is_quota_file())
+		return TRUE;
+	return FALSE;
+}
 
+/* ------------------------------------------------------------------------ */
+/* display_extended                                                         */
+/* ------------------------------------------------------------------------ */
+int display_extended(void)
+{
+	struct gfs2_inode *tmp_inode;
+	struct gfs2_buffer_head *tmp_bh;
+
+	/* Display any indirect pointers that we have. */
+	if (display_indirect() == 0)
+		return -1;
+	else if (block_is_rindex()) {
 		tmp_bh = bread(&sbd, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
-		print_rindex(tmp_inode);
+		parse_rindex(tmp_inode, TRUE);
 		brelse(tmp_bh, not_updated);
 	}
-	else if (!gfs1 && block == masterblock("inum")) {
-		struct gfs2_buffer_head *tmp_bh;
-
+	else if (block_is_rglist()) {
+		tmp_bh = bread(&sbd, masterblock("rindex"));
+		tmp_inode = inode_get(&sbd, tmp_bh);
+		parse_rindex(tmp_inode, FALSE);
+		brelse(tmp_bh, not_updated);
+	}
+	else if (block_is_jindex()) {
+		tmp_bh = bread(&sbd, block);
+		tmp_inode = inode_get(&sbd, tmp_bh);
+		print_jindex(tmp_inode);
+		brelse(tmp_bh, not_updated);
+	}
+	else if (block_is_inum_file()) {
 		tmp_bh = bread(&sbd, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_inum(tmp_inode);
 		brelse(tmp_bh, not_updated);
 	}
-	else if (!gfs1 && block == masterblock("statfs")) {
-		struct gfs2_buffer_head *tmp_bh;
-
+	else if (block_is_statfs_file()) {
 		tmp_bh = bread(&sbd, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_statfs(tmp_inode);
 		brelse(tmp_bh, not_updated);
 	}
-	else if ((gfs1 && block == gfs1_quota_di.no_addr) ||
-			 (block == masterblock("quota"))) {
-		struct gfs2_buffer_head *tmp_bh;
-
+	else if (block_is_quota_file()) {
 		tmp_bh = bread(&sbd, block);
 		tmp_inode = inode_get(&sbd, tmp_bh);
 		print_quota(tmp_inode);
@@ -823,7 +1141,7 @@
 
 	sbd1 = (struct gfs_sb *)&sbd.sd_sb;
 	ioctl(fd, BLKFLSBUF, 0);
-	do_lseek(fd, 0x10 * bufsize);
+	do_lseek(fd, 0x10 * 4096);
 	do_read(fd, buf, bufsize); /* read in the desired block */
 	memset(&sbd, 0, sizeof(struct gfs2_sbd));
 	sbd.device_fd = fd;
@@ -853,6 +1171,8 @@
 	}
 	else
 		gfs1 = FALSE;
+	bufsize = sbd.sd_sb.sb_bsize;
+	block = 0x10 * (4096 / bufsize);
 }
 
 /* ------------------------------------------------------------------------ */
@@ -871,26 +1191,54 @@
 /* ------------------------------------------------------------------------ */
 /* display                                                                  */
 /* ------------------------------------------------------------------------ */
-int display(enum dsp_mode display_mode, int identify_only)
+int display(int identify_only)
 {
+	uint64_t blk;
+
+	if (block == RGLIST_DUMMY_BLOCK)
+		blk = masterblock("rindex");
+	else
+		blk = block;
 	if (termlines) {
 		display_title_lines();
 		move(2,0);
 	}
-	if (block_in_mem != block) { /* If we changed blocks from the last read */
-		dev_offset = block * bufsize;
+	if (block_in_mem != blk) { /* If we changed blocks from the last read */
+		dev_offset = blk * bufsize;
 		ioctl(fd, BLKFLSBUF, 0);
 		do_lseek(fd, dev_offset);
 		do_read(fd, buf, bufsize); /* read in the desired block */
-		block_in_mem = block; /* remember which block is in memory */
+		block_in_mem = blk; /* remember which block is in memory */
 	}
 	line = 1;
 	gfs2_struct_type = display_block_type(buf);
 	if (identify_only)
 		return 0;
 	indirect_blocks = 0;
-	if (gfs2_struct_type == GFS2_METATYPE_SB || block == 0x10)
+	lines_per_row[dmode] = 1;
+	if (gfs2_struct_type == GFS2_METATYPE_SB || blk == 0x10 * (4096 / bufsize)) {
 		gfs2_sb_in(&sbd.sd_sb, buf); /* parse it out into the sb structure */
+		memset(&indirect, 0, sizeof(indirect));
+		indirect[0].block = sbd.sd_sb.sb_master_dir.no_addr;
+		indirect[0].is_dir = TRUE;
+		indirect[0].dirents = 2;
+
+		memcpy(&indirect[0].dirent[0].filename, "root", 4);
+		indirect[0].dirent[0].dirent.de_inum.no_formal_ino =
+			sbd.sd_sb.sb_root_dir.no_formal_ino;
+		indirect[0].dirent[0].dirent.de_inum.no_addr =
+			sbd.sd_sb.sb_root_dir.no_addr;
+		indirect[0].dirent[0].block = sbd.sd_sb.sb_root_dir.no_addr;
+		indirect[0].dirent[0].dirent.de_type = DT_DIR;
+
+		memcpy(&indirect[0].dirent[1].filename, "master", 7);
+		indirect[0].dirent[1].dirent.de_inum.no_formal_ino = 
+			sbd.sd_sb.sb_master_dir.no_formal_ino;
+		indirect[0].dirent[1].dirent.de_inum.no_addr =
+			sbd.sd_sb.sb_master_dir.no_addr;
+		indirect[0].dirent[1].block = sbd.sd_sb.sb_master_dir.no_addr;
+		indirect[0].dirent[1].dirent.de_type = DT_DIR;
+	}
 	else if (gfs2_struct_type == GFS2_METATYPE_DI) {
 		gfs2_dinode_in(&di, buf); /* parse disk inode into structure */
 		do_dinode_extended(&di, buf); /* get extended data, if any */
@@ -905,7 +1253,8 @@
 		indirect_blocks = 1;
 		memset(&indirect, 0, sizeof(indirect));
 		/* Directory Entries: */
-		for (x = sizeof(struct gfs2_leaf); x < bufsize; x += de.de_rec_len) {
+		for (x = sizeof(struct gfs2_leaf); x < bufsize;
+		     x += de.de_rec_len) {
 			gfs2_dirent_in(&de, buf + x);
 			if (de.de_inum.no_addr) {
 				indirect[indirect_blocks].block = de.de_inum.no_addr;
@@ -917,16 +1266,31 @@
 				indirect[indirect_blocks].is_dir = TRUE;
 				indirect[indirect_blocks].dirents++;
 			}
+			if (de.de_rec_len <= sizeof(struct gfs2_dirent))
+				break;
 		}
 	}
-	edit_last[display_mode] = 0;
-	if (display_mode == HEX_MODE)          /* if hex display mode           */
-		hexdump(dev_offset, buf, (gfs2_struct_type == GFS2_METATYPE_DI)?
-				struct_len + di.di_size:bufsize); /* show block in hex */
-	else if (display_mode == GFS2_MODE)    /* if structure display          */
-		display_gfs2();                    /* display the gfs2 structure    */
-	else                                   /* otherwise                     */
-		display_extended();                /* display extended blocks       */
+	last_entry_onscreen[dmode] = 0;
+	if (dmode == EXTENDED_MODE && !block_has_extended_info())
+		dmode = HEX_MODE;
+	if (termlines) {
+		move(termlines, 63);
+		if (dmode==HEX_MODE)
+			printw("Mode: Hex %s", (editing?"edit ":"view "));
+		else
+			printw("Mode: %s", (dmode==GFS2_MODE?"Structure":
+					    "Pointers "));
+		move(line, 0);
+	}
+	if (dmode == HEX_MODE)          /* if hex display mode           */
+		hexdump(dev_offset, buf,
+			(gfs2_struct_type == GFS2_METATYPE_DI)?
+			struct_len + di.di_size:bufsize);
+	else if (dmode == GFS2_MODE)    /* if structure display          */
+		display_gfs2();            /* display the gfs2 structure    */
+	else
+		display_extended();        /* display extended blocks       */
+	/* No else here because display_extended can switch back to hex mode */
 	if (termlines)
 		refresh();
 	return(0);
@@ -937,14 +1301,19 @@
 /* ------------------------------------------------------------------------ */
 void push_block(uint64_t blk)
 {
-	int i;
+	int i, bhst;
 
+	bhst = blockhist % BLOCK_STACK_SIZE;
 	if (blk) {
-		blockstack[blockhist % BLOCK_STACK_SIZE].display_mode = display_mode;
-		for (i = 0; i < DISPLAY_MODES; i++) {
-			blockstack[blockhist % BLOCK_STACK_SIZE].edit_row[i] = edit_row[i];
-			blockstack[blockhist % BLOCK_STACK_SIZE].edit_col[i] = edit_col[i];
+		blockstack[bhst].dmode = dmode;
+		for (i = 0; i < DMODES; i++) {
+			blockstack[bhst].start_row[i] = start_row[i];
+			blockstack[bhst].end_row[i] = end_row[i];
+			blockstack[bhst].edit_row[i] = edit_row[i];
+			blockstack[bhst].edit_col[i] = edit_col[i];
+			blockstack[bhst].lines_per_row[i] = lines_per_row[i];
 		}
+		blockstack[bhst].gfs2_struct_type = gfs2_struct_type;
 		blockhist++;
 		blockstack[blockhist % BLOCK_STACK_SIZE].block = blk;
 	}
@@ -955,17 +1324,22 @@
 /* ------------------------------------------------------------------------ */
 uint64_t pop_block(void)
 {
-	int i;
+	int i, bhst;
 
 	if (!blockhist)
 		return block;
 	blockhist--;
-	display_mode = blockstack[blockhist % BLOCK_STACK_SIZE].display_mode;
-	for (i = 0; i < DISPLAY_MODES; i++) {
-		edit_row[i] = blockstack[blockhist % BLOCK_STACK_SIZE].edit_row[i];
-		edit_col[i] = blockstack[blockhist % BLOCK_STACK_SIZE].edit_col[i];
+	bhst = blockhist % BLOCK_STACK_SIZE;
+	dmode = blockstack[bhst].dmode;
+	for (i = 0; i < DMODES; i++) {
+		start_row[i] = blockstack[bhst].start_row[i];
+		end_row[i] = blockstack[bhst].end_row[i];
+		edit_row[i] = blockstack[bhst].edit_row[i];
+		edit_col[i] = blockstack[bhst].edit_col[i];
+		lines_per_row[i] = blockstack[bhst].lines_per_row[i];
 	}
-	return blockstack[blockhist % BLOCK_STACK_SIZE].block;
+	gfs2_struct_type = blockstack[bhst].gfs2_struct_type;
+	return blockstack[bhst].block;
 }
 
 /* ------------------------------------------------------------------------ */
@@ -973,16 +1347,20 @@
 /* ------------------------------------------------------------------------ */
 uint64_t goto_block(void)
 {
-	uint64_t temp_blk;
 	char string[256];
+	int ch;
 
 	memset(string, 0, sizeof(string));
 	sprintf(string,"%"PRId64, block);
-	if (bobgets(string, 1, 7, 16)) {
+	if (bobgets(string, 1, 7, 16, &ch)) {
 		if (!strcmp(string,"root"))
 			temp_blk = sbd.sd_sb.sb_root_dir.no_addr;
-		else if (!gfs1 && !strcmp(string,"master"))
-			temp_blk = sbd.sd_sb.sb_master_dir.no_addr;
+		else if (!strcmp(string,"master")) {
+			if (!gfs1)
+				temp_blk = sbd.sd_sb.sb_master_dir.no_addr;
+			else
+				; /* maybe put out an error message at some point */
+		}
 		else if (isalpha(string[0])) {
 			if (gfs1) {
 				if (!strcmp(string, "jindex"))
@@ -992,15 +1370,19 @@
 				else if (!strcmp(string, "quota"))
 					temp_blk = gfs1_quota_di.no_addr;
 			}
-			else
-				temp_blk = masterblock(string);
+			else {
+				if (!strcmp(string, "rgs"))
+					temp_blk = RGLIST_DUMMY_BLOCK;
+				else
+					temp_blk = masterblock(string);
+			}
 		}
 		else if (string[0] == '0' && string[1] == 'x')
 			sscanf(string, "%"SCNx64, &temp_blk); /* retrieve in hex */
 		else
 			sscanf(string, "%" PRIu64, &temp_blk); /* retrieve decimal */
 
-		if (temp_blk < max_block) {
+		if (temp_blk == RGLIST_DUMMY_BLOCK || temp_blk < max_block) {
 			offset = 0;
 			block = temp_blk;
 			push_block(block);
@@ -1016,22 +1398,159 @@
 {
 
 	if (color_scheme) {
-		init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);  /* title lines */
-		init_pair(COLOR_NORMAL, COLOR_WHITE,  COLOR_BLACK); /* normal text */
-		init_pair(COLOR_INVERSE, COLOR_BLACK,  COLOR_WHITE); /* inverse text */
-		init_pair(COLOR_SPECIAL, COLOR_RED,    COLOR_BLACK); /* special text */
-		init_pair(COLOR_HIGHLIGHT, COLOR_GREEN, COLOR_BLACK); /* highlighted */
-		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_BLACK); /* offsets */
-		init_pair(COLOR_CONTENTS, COLOR_YELLOW, COLOR_BLACK); /* file data */
+		init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
+		init_pair(COLOR_NORMAL, COLOR_WHITE,  COLOR_BLACK);
+		init_pair(COLOR_INVERSE, COLOR_BLACK,  COLOR_WHITE);
+		init_pair(COLOR_SPECIAL, COLOR_RED,    COLOR_BLACK);
+		init_pair(COLOR_HIGHLIGHT, COLOR_GREEN, COLOR_BLACK);
+		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_BLACK);
+		init_pair(COLOR_CONTENTS, COLOR_YELLOW, COLOR_BLACK);
 	}
 	else {
-		init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);  /* title lines */
-		init_pair(COLOR_NORMAL, COLOR_BLACK,  COLOR_WHITE); /* normal text */
-		init_pair(COLOR_INVERSE, COLOR_WHITE,  COLOR_BLACK); /* inverse text */
-		init_pair(COLOR_SPECIAL, COLOR_RED,    COLOR_WHITE); /* special text */
-		init_pair(COLOR_HIGHLIGHT, COLOR_GREEN, COLOR_WHITE); /* highlighted */
-		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_WHITE); /* offsets */
-		init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE); /* file data */
+		init_pair(COLOR_TITLE, COLOR_BLACK,  COLOR_CYAN);
+		init_pair(COLOR_NORMAL, COLOR_BLACK,  COLOR_WHITE);
+		init_pair(COLOR_INVERSE, COLOR_WHITE,  COLOR_BLACK);
+		init_pair(COLOR_SPECIAL, COLOR_RED,    COLOR_WHITE);
+		init_pair(COLOR_HIGHLIGHT, COLOR_MAGENTA, COLOR_WHITE);
+		init_pair(COLOR_OFFSETS, COLOR_CYAN,   COLOR_WHITE);
+		init_pair(COLOR_CONTENTS, COLOR_BLUE, COLOR_WHITE);
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* hex_edit - Allow the user to edit the page by entering hex digits        */
+/* ------------------------------------------------------------------------ */
+void hex_edit(int *exitch)
+{
+	int left_off;
+	int ch;
+
+	left_off = ((block * bufsize) < 0xffffffff) ? 9 : 17;
+	/* 8 and 16 char addresses on screen */
+	
+	if (bobgets(estring, edit_row[dmode] + 3,
+		    (edit_col[dmode] * 2) + (edit_col[dmode] / 4) + left_off,
+		    2, exitch)) {
+		if (strstr(edit_fmt,"X") || strstr(edit_fmt,"x")) {
+			int hexoffset;
+			int i, sl = strlen(estring);
+			
+			for (i = 0; i < sl; i+=2) {
+				hexoffset = (edit_row[dmode] * 16) +
+					edit_col[dmode] + (i / 2);
+				ch = 0x00;
+				if (isdigit(estring[i]))
+					ch = (estring[i] - '0') * 0x10;
+				else if (estring[i] >= 'a' &&
+					 estring[i] <= 'f')
+					ch = (estring[i]-'a' + 0x0a)*0x10;
+				else if (estring[i] >= 'A' &&
+					 estring[i] <= 'F')
+					ch = (estring[i] - 'A' + 0x0a) * 0x10;
+				if (isdigit(estring[i+1]))
+					ch += (estring[i+1] - '0');
+				else if (estring[i+1] >= 'a' &&
+					 estring[i+1] <= 'f')
+					ch += (estring[i+1] - 'a' + 0x0a);
+				else if (estring[i+1] >= 'A' &&
+					 estring[i+1] <= 'F')
+					ch += (estring[i+1] - 'A' + 0x0a);
+				buf[offset + hexoffset] = ch;
+			}
+			do_lseek(fd, dev_offset);
+			do_write(fd, buf, bufsize);
+			fsync(fd);
+		}
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* page up                                                                  */
+/* ------------------------------------------------------------------------ */
+void pageup(void)
+{
+	if (dmode == EXTENDED_MODE) {
+		int dsplines = termlines - 6;
+		
+		if (edit_row[dmode] - (dsplines / lines_per_row[dmode]) > 0) {
+			start_row[dmode] -= (dsplines / lines_per_row[dmode]);
+			edit_row[dmode] -= (dsplines / lines_per_row[dmode]);
+		}
+		else {
+			start_row[dmode] = 0;
+			edit_row[dmode] = 0;
+		}
+	}
+	else {
+		start_row[dmode] = edit_row[dmode] = 0;
+		if (dmode == GFS2_MODE || offset==0) {
+			block--;
+			if (dmode == HEX_MODE)
+				offset = (bufsize % screen_chunk_size) > 0 ? 
+					screen_chunk_size *
+					(bufsize / screen_chunk_size) :
+					bufsize - screen_chunk_size;
+			else
+				offset = 0;
+		}
+		else
+			offset -= screen_chunk_size;
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* page down                                                                */
+/* ------------------------------------------------------------------------ */
+void pagedn(void)
+{
+	if (dmode == EXTENDED_MODE) {
+		int dsplines = termlines - 6;
+
+		if ((edit_row[dmode] + dsplines) / lines_per_row[dmode] + 1 <
+		    end_row[dmode]) {
+			start_row[dmode] += dsplines / lines_per_row[dmode];
+			edit_row[dmode] += dsplines / lines_per_row[dmode];
+		}
+		else
+			edit_row[dmode] = end_row[dmode] - 1;
+	}
+	else {
+		start_row[dmode] = edit_row[dmode] = 0;
+		if (dmode == GFS2_MODE ||
+		    offset + screen_chunk_size >= bufsize) {
+			block++;
+			offset = 0;
+		}
+		else
+			offset += screen_chunk_size;
+	}
+}
+
+/* ------------------------------------------------------------------------ */
+/* jump - jump to the address the cursor is on                              */
+/* ------------------------------------------------------------------------ */
+void jump(void)
+{
+	if (dmode == HEX_MODE) {
+		unsigned int col2;
+		uint64_t *b;
+		
+		col2 = edit_col[dmode] & 0x08;/* thus 0-7->0, 8-15->8 */
+		b = (uint64_t *)&buf[edit_row[dmode]*16 + offset + col2];
+		temp_blk=be64_to_cpu(*b);
+	}
+	else
+		sscanf(estring, "%"SCNx64, &temp_blk);/* retrieve in hex */
+	if (temp_blk < max_block) { /* if the block number is valid */
+		int i;
+		
+		offset = 0;
+		block = temp_blk;
+		push_block(block);
+		for (i = 0; i < DMODES; i++) {
+			start_row[i] = end_row[i] = edit_row[i] = 0;
+			edit_col[i] = 0;
+		}
 	}
 }
 
@@ -1041,8 +1560,6 @@
 void interactive_mode(void)
 {
 	int ch, Quit;
-	int64_t temp_blk;
-	int left_off;
 
 	if ((wind = initscr()) == NULL) {
 		fprintf(stderr, "Error: unable to initialize screen.");
@@ -1062,240 +1579,223 @@
 	init_colors();
 	/* Accept keystrokes and act on them accordingly */
 	Quit = FALSE;
+	editing = FALSE;
 	while (!Quit) {
-		display(display_mode, FALSE);
-		while ((ch=getch()) == 0); // wait for input
+		display(FALSE);
+		if (editing) {
+			if (edit_row[dmode] == -1)
+				block = goto_block();
+			else {
+				if (dmode == HEX_MODE)
+					hex_edit(&ch);
+				else if (dmode == GFS2_MODE)
+					bobgets(estring, edit_row[dmode]+4, 24,
+						edit_size[dmode], &ch);
+				else
+					bobgets(estring, edit_row[dmode]+6, 14,
+						edit_size[dmode], &ch);
+			}
+		}
+		else
+			while ((ch=getch()) == 0); // wait for input
+
 		switch (ch)
 		{
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* escape or 'q' */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 0x1b:
 		case 0x03:
 		case 'q':
-			Quit=TRUE;
+			if (editing)
+				editing = FALSE;
+			else
+				Quit=TRUE;
 			break;
-		/* -------------------------------------------------------------- */
-		/* home - return to the superblock                                */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
+		/* home - return to the superblock                           */
+		/* --------------------------------------------------------- */
 		case KEY_HOME:
-			block = 0x10;
-			push_block(block);
-			offset = 0;
+			if (dmode == EXTENDED_MODE) {
+				start_row[dmode] = end_row[dmode] = 0;
+				edit_row[dmode] = 0;
+			}
+			else {
+				block = 0x10 * (4096 / bufsize);
+				push_block(block);
+				offset = 0;
+			}
 			break;
-		/* -------------------------------------------------------------- */
-		/* backspace - return to the previous block on the stack          */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
+		/* backspace - return to the previous block on the stack     */
+		/* --------------------------------------------------------- */
 		case KEY_BACKSPACE:
 		case 0x7f:
 			block = pop_block();
 			offset = 0;
 			break;
-		/* -------------------------------------------------------------- */
-		/* space - go down the block stack (opposite of backspace)        */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
+		/* space - go down the block stack (opposite of backspace)   */
+		/* --------------------------------------------------------- */
 		case ' ':
 			blockhist++;
 			block = blockstack[blockhist % BLOCK_STACK_SIZE].block;
 			offset = 0;
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* arrow up */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case KEY_UP:
-			if (edit_row[display_mode] >= 0) /* -1 means change block number */
-				edit_row[display_mode]--;
+			if (dmode == EXTENDED_MODE) {
+				if (edit_row[dmode] > 0)
+					edit_row[dmode]--;
+				if (edit_row[dmode] < start_row[dmode])
+					start_row[dmode] = edit_row[dmode];
+			}
+			else {
+				if (edit_row[dmode] >= 0)
+					edit_row[dmode]--;
+			}
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* arrow down */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case KEY_DOWN:
-			if (edit_row[display_mode] < edit_last[display_mode])
-				edit_row[display_mode]++;
+			if (dmode == EXTENDED_MODE) {
+				if (edit_row[dmode] + 1 < end_row[dmode]) {
+					if (edit_row[dmode] >= last_entry_onscreen[dmode])
+						start_row[dmode]++;
+					edit_row[dmode]++;
+				}
+			}
+			else {
+				if (edit_row[dmode] < last_entry_onscreen[dmode])
+					edit_row[dmode]++;
+			}
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* arrow left */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case KEY_LEFT:
-			if (display_mode == HEX_MODE) {
-				if (edit_col[display_mode] > 0)
-					edit_col[display_mode]--;
+			if (dmode == HEX_MODE) {
+				if (edit_col[dmode] > 0)
+					edit_col[dmode]--;
 				else
-					edit_col[display_mode] = 15;
+					edit_col[dmode] = 15;
 			}
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* arrow right */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case KEY_RIGHT:
-			if (display_mode == HEX_MODE) {
-				if (edit_col[display_mode] < 15)
-					edit_col[display_mode]++;
+			if (dmode == HEX_MODE) {
+				if (edit_col[dmode] < 15)
+					edit_col[dmode]++;
 				else
-					edit_col[display_mode] = 0;
+					edit_col[dmode] = 0;
 			}
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* m - change display mode key */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'm':
-			display_mode = ((display_mode + 1) % DISPLAY_MODES);
+			dmode = ((dmode + 1) % DMODES);
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* J - Jump to highlighted block number */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'j':
-			if (display_mode == HEX_MODE) {
-				unsigned int col2;
-				uint64_t *b;
-
-				col2 = edit_col[display_mode] & 0x08;/* thus 0-7->0, 8-15->8 */
-				b = (uint64_t *)&buf[edit_row[display_mode]*16 + offset + col2];
-				temp_blk=be64_to_cpu(*b);
-			}
-			else
-				sscanf(edit_string, "%"SCNx64, &temp_blk);/* retrieve in hex */
-			if (temp_blk < max_block) { /* if the block number is valid */
-				int i;
-
-				offset = 0;
-				block = temp_blk;
-				push_block(block);
-				for (i = 0; i < DISPLAY_MODES; i++) {
-					edit_row[i] = 0;
-					edit_col[i] = 0;
-				}
-			}
+			jump();
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* g - goto block */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'g':
 			block = goto_block();
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* h - help key */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'h':
 			print_usage();
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
+		/* e - change to extended mode */
+		/* --------------------------------------------------------- */
+		case 'e':
+			dmode = EXTENDED_MODE;
+			break;
+		/* --------------------------------------------------------- */
 		/* b - Back one 4K block */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'b':
-			edit_row[display_mode] = 0;
-			if (block > 0) {
+			start_row[dmode] = end_row[dmode] = edit_row[dmode] = 0;
+			if (block > 0)
 				block--;
-			}
 			offset = 0;
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* c - Change color scheme */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'c':
 			color_scheme = !color_scheme;
 			init_colors();
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* page up key */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 0x19:                    // ctrl-y for vt100
 		case KEY_PPAGE:		      // PgUp
 		case 0x15:                    // ctrl-u for vi compat.
 		case 0x02:                   // ctrl-b for less compat.
-			edit_row[display_mode] = 0;
-			if (display_mode == GFS2_MODE || offset==0) {
-				block--;
-				if (display_mode == HEX_MODE)
-					offset = (bufsize % screen_chunk_size) > 0 ? 
-						screen_chunk_size * (bufsize / screen_chunk_size) :
-						bufsize - screen_chunk_size;
+			pageup();
+			break;
+		/* --------------------------------------------------------- */
+		/* end - Jump to the end of the list */
+		/* --------------------------------------------------------- */
+		case 0x168:
+			if (dmode == EXTENDED_MODE) {
+				int dsplines = termlines - 6;
+				int ents_per_screen = dsplines /
+					lines_per_row[dmode];
+
+				edit_row[dmode] = end_row[dmode] - 1;
+				if ((edit_row[dmode] - ents_per_screen)+1 > 0)
+					start_row[dmode] = edit_row[dmode] - 
+						ents_per_screen + 1;
 				else
-					offset = 0;
+					start_row[dmode] = 0;
 			}
-			else
-				offset -= screen_chunk_size;
+			/* TODO: Make end key work for other display modes. */
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* f - Forward one 4K block */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 'f':
-			edit_row[display_mode] = 0;
+			start_row[dmode]=end_row[dmode]=edit_row[dmode] = 0;
+			lines_per_row[dmode] = 1;
 			block++;
 			offset = 0;
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* page down key */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case 0x16:                    // ctrl-v for vt100
 		case KEY_NPAGE:		      // PgDown
 		case 0x04:                    // ctrl-d for vi compat.
-			edit_row[display_mode] = 0;
-			if (display_mode == GFS2_MODE ||
-				offset + screen_chunk_size >= bufsize) {
-				block++;
-				offset = 0;
-			}
-			else
-				offset += screen_chunk_size;
+			pagedn();
 			break;
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		/* enter key - change a value */
-		/* -------------------------------------------------------------- */
+		/* --------------------------------------------------------- */
 		case(KEY_ENTER):
 		case('\n'):
 		case('\r'):
-			if (edit_row[display_mode] == -1)
-				block = goto_block();
-			else {
-				if (display_mode == HEX_MODE) {
-					left_off = ((block * bufsize) < 0xffffffff) ? 9 : 17;
-					/* 8 and 16 char addresses on screen */
-					       
-					if (bobgets(edit_string, edit_row[display_mode] + 3,
-								(edit_col[display_mode] * 2) + 
-								(edit_col[display_mode] / 4) + left_off, 2)) {
-						if (strstr(edit_fmt,"X") || strstr(edit_fmt,"x")) {
-							int hexoffset;
-							unsigned char ch;
-							
-							hexoffset = (edit_row[display_mode] * 16) +
-								edit_col[display_mode];
-							ch = 0x00;
-							if (isdigit(edit_string[0]))
-								ch = (edit_string[0] - '0') * 0x10;
-							else if (edit_string[0] >= 'a' &&
-									 edit_string[0] <= 'f')
-								ch = (edit_string[0] - 'a' + 0x0a) * 0x10;
-							else if (edit_string[0] >= 'A' &&
-									 edit_string[0] <= 'F')
-								ch = (edit_string[0] - 'A' + 0x0a) * 0x10;
-							if (isdigit(edit_string[1]))
-								ch += (edit_string[1] - '0');
-							else if (edit_string[1] >= 'a' &&
-									 edit_string[1] <= 'f')
-								ch += (edit_string[1] - 'a' + 0x0a);
-							else if (edit_string[1] >= 'A' &&
-									 edit_string[1] <= 'F')
-								ch += (edit_string[1] - 'A' + 0x0a);
-							buf[offset + hexoffset] = ch;
-							do_lseek(fd, dev_offset);
-							do_write(fd, buf, bufsize);
-							fsync(fd);
-						}
-					}
-				}
-				else if (display_mode == GFS2_MODE)
-					bobgets(edit_string, edit_row[display_mode] + 4, 24,
-							edit_size[display_mode]);
-				else
-					bobgets(edit_string, edit_row[display_mode] + 6, 14,
-							edit_size[display_mode]);
-			}
+			editing = !editing;
 			break;
 		default:
 			move(termlines - 1, 0);
-			printw("Keystroke not understood: %02X",ch);
+			printw("Keystroke not understood: 0x%03X",ch);
 			refresh();
 			sleep(1);
 			break;
@@ -1315,6 +1815,9 @@
 	fprintf(stderr,"\nFormat is: gfs2_edit [-c 1] [-V] [-x] [-h] [identify] [-p structures|blocks] /dev/device\n\n");
 	fprintf(stderr,"If only the device is specified, it enters into hexedit mode.\n");
 	fprintf(stderr,"identify - prints out only the block type, not the details.\n");
+	fprintf(stderr,"savemeta - save off your metadata for analysis and debugging.  The intelligent way (assume bitmap is correct).\n");
+	fprintf(stderr,"savemetaslow - save off your metadata for analysis and debugging.  The SLOW way (block by block).\n");
+	fprintf(stderr,"restoremeta - restore metadata for debugging (DANGEROUS).\n");
 	fprintf(stderr,"-V   prints version number.\n");
 	fprintf(stderr,"-c 1 selects alternate color scheme 1\n");
 	fprintf(stderr,"-p   prints GFS2 structures or blocks to stdout.\n");
@@ -1327,6 +1830,7 @@
 	fprintf(stderr,"     inum - prints the inum file.\n");
 	fprintf(stderr,"     statfs - prints the statfs file.\n");
 	fprintf(stderr,"     rindex - prints the rindex file.\n");
+	fprintf(stderr,"     rgs - prints all the resource groups (rgs).\n");
 	fprintf(stderr,"     quota - prints the quota file.\n");
 	fprintf(stderr,"-x   print in hexmode.\n");
 	fprintf(stderr,"-h   prints this help.\n\n");
@@ -1376,17 +1880,21 @@
 			else if (!strcasecmp(argv[i], "-p") ||
 					 !strcasecmp(argv[i], "-print")) {
 				termlines = 0; /* initial value--we'll figure it out later */
-				display_mode = GFS2_MODE;
+				dmode = GFS2_MODE;
 			}
+			else if (!strcasecmp(argv[i], "savemeta"))
+				savemeta(argv[i+1], argv[i+2], FALSE);
+			else if (!strcasecmp(argv[i], "savemetaslow"))
+				savemeta(argv[i+1], argv[i+2], TRUE);
+			else if (!strcasecmp(argv[i], "restoremeta"))
+				restoremeta(argv[i+1], argv[i+2]);
 			else if (strchr(argv[i],'/'))
 				strcpy(device, argv[i]);
 		}
 		else { /* second pass */
 			if (!termlines && !strchr(argv[i],'/')) { /* if print, no slash */
-				uint64_t temp_blk;
-
 				if (!strcasecmp(argv[i], "-x"))
-					display_mode = HEX_MODE;
+					dmode = HEX_MODE;
 				else if (argv[i][0] == '-') /* if it starts with a dash */
 					; /* ignore it--meant for pass == 0 */
 				else if (!strcmp(argv[i], "identify"))
@@ -1396,12 +1904,16 @@
 						   max_block, max_block);
 				else if (!strcmp(argv[i], "sb") ||
 						 !strcmp(argv[i], "superblock"))
-					push_block(0x10); /* superblock */
+					push_block(0x10 * (4096 / bufsize)); /* superblock */
 				else if (!strcmp(argv[i], "root") ||
 						 !strcmp(argv[i], "rootdir"))
 					push_block(sbd.sd_sb.sb_root_dir.no_addr);
-				else if (!gfs1 && !strcmp(argv[i], "master"))
-					push_block(sbd.sd_sb.sb_master_dir.no_addr);
+				else if (!strcmp(argv[i], "master")) {
+					if (!gfs1)
+						push_block(sbd.sd_sb.sb_master_dir.no_addr);
+					else
+						fprintf(stderr, "This is GFS1; there's no master directory.\n");
+				}
 				else if (!strcmp(argv[i], "jindex")) {
 					if (gfs1)
 						push_block(sbd1->sb_jindex_di.no_addr);
@@ -1421,6 +1933,10 @@
 					else
 						push_block(masterblock("rindex"));
 				}
+				else if (!strcmp(argv[i], "rgs")) {
+					if (!gfs1)
+						push_block(RGLIST_DUMMY_BLOCK);
+				}
 				else if (!strcmp(argv[i], "quota")) {
 					if (gfs1)
 						push_block(gfs1_quota_di.no_addr);
@@ -1461,19 +1977,25 @@
 
 	prog_name = argv[0];
 
+	memset(start_row, 0, sizeof(start_row));
+	memset(lines_per_row, 0, sizeof(lines_per_row));
+	memset(end_row, 0, sizeof(end_row));
 	memset(edit_row, 0, sizeof(edit_row));
 	memset(edit_col, 0, sizeof(edit_col));
 	memset(edit_size, 0, sizeof(edit_size));
-	memset(edit_last, 0, sizeof(edit_last));
-	display_mode = HEX_MODE;
+	memset(last_entry_onscreen, 0, sizeof(last_entry_onscreen));
+	dmode = HEX_MODE;
 	type_alloc(buf, char, bufsize); /* allocate/malloc a new 4K buffer */
 	block = 0x10;
 	for (i = 0; i < BLOCK_STACK_SIZE; i++) {
-		blockstack[i].display_mode = display_mode;
+		blockstack[i].dmode = dmode;
 		blockstack[i].block = block;
-		for (j = 0; j < DISPLAY_MODES; j++) {
+		for (j = 0; j < DMODES; j++) {
+			blockstack[i].start_row[j] = 0;
+			blockstack[i].end_row[j] = 0;
 			blockstack[i].edit_row[j] = 0;
 			blockstack[i].edit_col[j] = 0;
+			blockstack[i].lines_per_row[j] = 0;
 		}
 	}
 
@@ -1498,7 +2020,7 @@
 	else { /* print all the structures requested */
 		for (i = 0; i <= blockhist; i++) {
 			block = blockstack[i + 1].block;
-			display(display_mode, identify);
+			display(identify);
 			if (!identify) {
 				display_extended();
 				printf("-------------------------------------" \
--- cluster/gfs2/edit/hexedit.h	2006/11/14 20:13:36	1.4.2.2
+++ cluster/gfs2/edit/hexedit.h	2007/06/26 01:40:43	1.4.2.3
@@ -39,7 +39,7 @@
 #define INIT(X) =X 
 #endif
 
-#define DISPLAY_MODES 3
+#define DMODES 3
 enum dsp_mode { HEX_MODE = 0, GFS2_MODE = 1, EXTENDED_MODE = 2 };
 #define BLOCK_STACK_SIZE 256
 
@@ -64,7 +64,7 @@
 EXTERN int edit_mode INIT(0);
 EXTERN int line;
 EXTERN char edit_fmt[80];
-EXTERN char edit_string[1024];
+EXTERN char estring[1024]; /* edit string */
 EXTERN uint64_t dev_offset INIT(0);
 EXTERN uint64_t max_block INIT(0);
 EXTERN char *buf INIT(NULL);
@@ -76,9 +76,10 @@
 EXTERN int line INIT(1);
 EXTERN int struct_len INIT(0);
 EXTERN unsigned int offset;
-EXTERN int edit_row[DISPLAY_MODES], edit_col[DISPLAY_MODES];
-EXTERN int edit_size[DISPLAY_MODES], edit_last[DISPLAY_MODES];
-EXTERN char edit_string[1024], edit_fmt[80];
+EXTERN int edit_row[DMODES], edit_col[DMODES], print_entry_ndx;
+EXTERN int start_row[DMODES], end_row[DMODES], lines_per_row[DMODES];
+EXTERN int edit_size[DMODES], last_entry_onscreen[DMODES];
+EXTERN char edit_fmt[80];
 EXTERN struct gfs2_sbd sbd;
 EXTERN struct gfs_sb *sbd1;
 EXTERN struct gfs2_inum gfs1_quota_di;   /* kludge because gfs2 sb too small */
@@ -92,6 +93,8 @@
 EXTERN int color_scheme INIT(0);
 EXTERN WINDOW *wind;
 EXTERN int gfs1 INIT(0);
+EXTERN int editing INIT(0);
+EXTERN uint64_t temp_blk;
 
 struct gfs2_dirents {
 	uint64_t block;
@@ -114,9 +117,17 @@
 
 struct blkstack_info {
 	uint64_t block;
-	int edit_row[DISPLAY_MODES];
-	int edit_col[DISPLAY_MODES];
-	enum dsp_mode display_mode;
+	int start_row[DMODES];
+	int end_row[DMODES];
+	int lines_per_row[DMODES];
+	int edit_row[DMODES];
+	int edit_col[DMODES];
+	enum dsp_mode dmode;
+	int gfs2_struct_type;
+};
+
+struct metapath {
+	uint64_t mp_list[GFS2_MAX_META_HEIGHT];
 };
 
 struct gfs_sb {
@@ -148,13 +159,21 @@
 	char sb_reserved[96];
 };
 
+struct gfs_jindex {
+        uint64_t ji_addr;       /* starting block of the journal */
+        uint32_t ji_nsegment;   /* number (quantity) of segments in journal */
+        uint32_t ji_pad;
+
+        char ji_reserved[64];
+};
+
 EXTERN struct blkstack_info blockstack[BLOCK_STACK_SIZE];
 EXTERN struct indirect_info indirect[512]; /* more than the most indirect
 											  pointers possible for any given
 											  4K block */
 EXTERN struct indirect_info masterdir; /* Master directory info */
 EXTERN int indirect_blocks INIT(0);  /* count of indirect blocks */
-EXTERN enum dsp_mode display_mode INIT(HEX_MODE);
+EXTERN enum dsp_mode dmode INIT(HEX_MODE);
 
 #define SCREEN_HEIGHT   (16)
 #define SCREEN_WIDTH    (16)
@@ -221,12 +240,54 @@
 #define COLOR_OFFSETS   6
 #define COLOR_CONTENTS  7
 
-#define COLORS_TITLE     do { attrset(COLOR_PAIR(COLOR_TITLE));attron(A_BOLD); } while (0)
-#define COLORS_NORMAL    do { attrset(COLOR_PAIR(COLOR_NORMAL));attron(A_BOLD); } while (0)
-#define COLORS_INVERSE   do { attrset(COLOR_PAIR(COLOR_INVERSE));attron(A_BOLD); } while (0)
-#define COLORS_SPECIAL   do { attrset(COLOR_PAIR(COLOR_SPECIAL));attron(A_BOLD); } while (0)
-#define COLORS_HIGHLIGHT do { attrset(COLOR_PAIR(COLOR_HIGHLIGHT));attron(A_BOLD); } while (0)
-#define COLORS_OFFSETS   do { attrset(COLOR_PAIR(COLOR_OFFSETS));attron(A_BOLD); } while (0)
-#define COLORS_CONTENTS  do { attrset(COLOR_PAIR(COLOR_CONTENTS));attron(A_BOLD); } while (0)
+#define COLORS_TITLE     \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_TITLE)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_NORMAL    \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_NORMAL)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_INVERSE   \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_INVERSE)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_SPECIAL   \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_SPECIAL)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_HIGHLIGHT \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_HIGHLIGHT)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_OFFSETS   \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_OFFSETS)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
+#define COLORS_CONTENTS  \
+	do { \
+		if (termlines) { \
+			attrset(COLOR_PAIR(COLOR_CONTENTS)); \
+			attron(A_BOLD); \
+		} \
+	} while (0)
 
 #endif /* __HEXVIEW_DOT_H__ */
--- cluster/gfs2/libgfs2/super.c	2007/05/01 18:20:50	1.3.2.1
+++ cluster/gfs2/libgfs2/super.c	2007/06/26 01:40:43	1.3.2.2
@@ -33,7 +33,7 @@
  *
  * Returns: 0 on success, -1 on failure
  */
-static int check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb)
+int check_sb(struct gfs2_sb *sb)
 {
 	if (sb->sb_header.mh_magic != GFS2_MAGIC ||
 	    sb->sb_header.mh_type != GFS2_METATYPE_SB) {
@@ -75,7 +75,7 @@
 	gfs2_sb_in(&sdp->sd_sb, bh->b_data);
 	brelse(bh, not_updated);
 
-	error = check_sb(sdp, &sdp->sd_sb);
+	error = check_sb(&sdp->sd_sb);
 	if (error)
 		goto out;
 




More information about the Cluster-devel mailing list