2007-12-31  Bean  <bean123ch@gmail.com>

	* include/grub/file.h (grub_fshook): New structure.
	(grub_fshook_register): New function.
	(grub_fshook_unregister): New function.
	(grub_open_file_raw): New function.

	* kern/file.c (grub_fshook_list): New variable.
	(grub_fshook_register): New function.
	(grub_fshook_unregister): New function.
	(grub_open_rfile): The original grub_open_file.
	(grub_open_file): New function.

	* io/gzio.c (grub_fshook_open): New function.
	(grub_fshook_gzio): New variable.
	
	* commands/cat.c (grub_cmd_cat): Replace grub_gzfile_open with grub_file_open.

	* commands/cmp.c (grub_cmd_cmp): Likewise.

	* commands/hexdump.c (grub_cmd_hexdump): Likewise.

	* kern/elf.c (grub_elf_open): Likewise.

	* loader/multiboot2.c (grub_multiboot2): Likewise.
	(grub_module2): Likewise.

	* loader/multiboot_loader.c (grub_rescue_cmd_multiboot_loader): Likewise.

	* loader/i386/pc/multiboot.c (grub_multiboot): Likewise.
	(grub_module): Likewise.

	* command/blocklist.c (grub_cmd_blocklist): Replace grub_file_open with grub_file_ropen.

	* util/i386/pc/grub-setup.c (setup): Likewise.


diff --git a/commands/blocklist.c b/commands/blocklist.c
index df0e632..fde5c58 100644
--- a/commands/blocklist.c
+++ b/commands/blocklist.c
@@ -82,7 +82,7 @@ grub_cmd_blocklist (struct grub_arg_list *state __attribute__ ((unused)),
   if (argc < 1)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
 
-  file = grub_file_open (args[0]);
+  file = grub_file_ropen (args[0]);
   if (! file)
     return grub_errno;
 
diff --git a/commands/cat.c b/commands/cat.c
index 35b4c14..c6db38b 100644
--- a/commands/cat.c
+++ b/commands/cat.c
@@ -24,7 +24,6 @@
 #include <grub/disk.h>
 #include <grub/term.h>
 #include <grub/misc.h>
-#include <grub/gzio.h>
 
 static grub_err_t
 grub_cmd_cat (struct grub_arg_list *state __attribute__ ((unused)),
@@ -38,7 +37,7 @@ grub_cmd_cat (struct grub_arg_list *state __attribute__ ((unused)),
   if (argc != 1)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
 
-  file = grub_gzfile_open (args[0], 1);
+  file = grub_file_open (args[0]);
   if (! file)
     return 0;
   
diff --git a/commands/cmp.c b/commands/cmp.c
index bb4de60..d7eaf4a 100644
--- a/commands/cmp.c
+++ b/commands/cmp.c
@@ -23,7 +23,6 @@
 #include <grub/misc.h>
 #include <grub/file.h>
 #include <grub/mm.h>
-#include <grub/gzio.h>
 
 #define BUFFER_SIZE 512
 
@@ -44,8 +43,8 @@ grub_cmd_cmp (struct grub_arg_list *state __attribute__ ((unused)),
   grub_printf ("Compare `%s' and `%s':\n", args[0],
 	       args[1]);
 
-  file1 = grub_gzfile_open (args[0], 1);
-  file2 = grub_gzfile_open (args[1], 1);
+  file1 = grub_file_open (args[0]);
+  file2 = grub_file_open (args[1]);
   if (! file1 || ! file2)
     goto cleanup;
 
diff --git a/commands/hexdump.c b/commands/hexdump.c
index d353d5e..a5d5f16 100644
--- a/commands/hexdump.c
+++ b/commands/hexdump.c
@@ -23,7 +23,6 @@
 #include <grub/file.h>
 #include <grub/disk.h>
 #include <grub/misc.h>
-#include <grub/gzio.h>
 #include <grub/hexdump.h>
 
 static const struct grub_arg_option options[] = {
@@ -100,7 +99,7 @@ grub_cmd_hexdump (struct grub_arg_list *state, int argc, char **args)
 
   if (is_file)
     {
-      file = grub_gzfile_open (args[0], 1);
+      file = grub_file_open (args[0]);
       if (!file)
 	return 0;
 
diff --git a/include/grub/file.h b/include/grub/file.h
index df2e9e4..008ebd0 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -48,9 +48,20 @@ struct grub_file
 };
 typedef struct grub_file *grub_file_t;
 
+struct grub_fshook
+{
+  grub_file_t (*open_func)(grub_file_t file);
+  struct grub_fshook *next;
+};
+typedef struct grub_fshook *grub_fshook_t;
+
+void EXPORT_FUNC(grub_fshook_register) (grub_fshook_t fshook);
+void EXPORT_FUNC(grub_fshook_unregister) (grub_fshook_t fshook);
+
 /* Get a device name from NAME.  */
 char *EXPORT_FUNC(grub_file_get_device_name) (const char *name);
 
+grub_file_t EXPORT_FUNC(grub_file_ropen) (const char *name);
 grub_file_t EXPORT_FUNC(grub_file_open) (const char *name);
 grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, char *buf,
 					  grub_size_t len);
diff --git a/io/gzio.c b/io/gzio.c
index 0fada6c..7696aa8 100644
--- a/io/gzio.c
+++ b/io/gzio.c
@@ -36,6 +36,7 @@
 
 #include <grub/err.h>
 #include <grub/types.h>
+#include <grub/dl.h>
 #include <grub/mm.h>
 #include <grub/misc.h>
 #include <grub/fs.h>
@@ -1241,3 +1242,25 @@ static struct grub_fs grub_gzio_fs =
     .label = 0,
     .next = 0
   };
+
+static grub_file_t grub_fshook_open(grub_file_t file)
+{
+  return grub_gzio_open (file, 1);
+}
+
+static struct grub_fshook grub_fshook_gzio =
+  {
+    .open_func = grub_fshook_open,
+    .next = 0
+  };
+
+GRUB_MOD_INIT(gzio)
+{
+  (void) mod;			/* To stop warning. */
+  grub_fshook_register(&grub_fshook_gzio);
+}
+
+GRUB_MOD_FINI(gzio)
+{
+  grub_fshook_unregister(&grub_fshook_gzio);
+}
diff --git a/kern/elf.c b/kern/elf.c
index b362949..948035d 100644
--- a/kern/elf.c
+++ b/kern/elf.c
@@ -21,7 +21,6 @@
 #include <grub/elf.h>
 #include <grub/elfload.h>
 #include <grub/file.h>
-#include <grub/gzio.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
 
@@ -96,7 +95,7 @@ grub_elf_open (const char *name)
 {
   grub_file_t file;
 
-  file = grub_gzfile_open (name, 1);
+  file = grub_file_open (name);
   if (! file)
     return 0;
 
diff --git a/kern/file.c b/kern/file.c
index adf55da..f19e823 100644
--- a/kern/file.c
+++ b/kern/file.c
@@ -23,6 +23,30 @@
 #include <grub/mm.h>
 #include <grub/fs.h>
 #include <grub/device.h>
+#include <grub/env.h>
+
+static grub_fshook_t grub_fshook_list;
+
+void
+grub_fshook_register (grub_fshook_t fshook)
+{
+  fshook->next = grub_fshook_list;
+  grub_fshook_list = fshook;
+}
+
+void
+grub_fshook_unregister (grub_fshook_t fshook)
+{
+  grub_fshook_t *p, q;
+
+  for (p = &grub_fshook_list, q = *p; q; p = &(q->next), q = q->next)
+    if (q == fshook)
+      {
+	*p = q->next;
+	break;
+      }
+}
+
 
 /* Get the device part of the filename NAME. It is enclosed by parentheses.  */
 char *
@@ -52,7 +76,7 @@ grub_file_get_device_name (const char *name)
 }
 
 grub_file_t
-grub_file_open (const char *name)
+grub_file_ropen (const char *name)
 {
   grub_device_t device;
   grub_file_t file = 0;
@@ -110,6 +134,34 @@ grub_file_open (const char *name)
   return 0;
 }
 
+grub_file_t
+grub_file_open (const char *name)
+{
+  grub_file_t file;
+  grub_fshook_t p;
+  char *val;
+
+  file=grub_file_ropen (name);
+
+  if (! file)
+    return file;
+
+  val= grub_env_get ("nofshook");
+  if ((val) && (val[0]=='1'))
+    return file;
+
+  for (p=grub_fshook_list;p;p=p->next)
+    {
+      grub_file_t new_file;
+
+      new_file = (*p->open_func) (file);
+      if (new_file)
+        return new_file;
+    }
+
+  return file;
+}
+
 grub_ssize_t
 grub_file_read (grub_file_t file, char *buf, grub_size_t len)
 {
diff --git a/loader/i386/pc/multiboot.c b/loader/i386/pc/multiboot.c
index 250ef47..772962b 100644
--- a/loader/i386/pc/multiboot.c
+++ b/loader/i386/pc/multiboot.c
@@ -42,7 +42,6 @@
 #include <grub/dl.h>
 #include <grub/mm.h>
 #include <grub/misc.h>
-#include <grub/gzio.h>
 
 extern grub_dl_t my_mod;
 static struct grub_multiboot_info *mbi;
@@ -253,7 +252,7 @@ grub_multiboot (int argc, char *argv[])
       goto fail;
     }
 
-  file = grub_gzfile_open (argv[0], 1);
+  file = grub_file_open (argv[0]);
   if (! file)
     {
       grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
@@ -362,7 +361,7 @@ grub_module  (int argc, char *argv[])
       goto fail;
     }
 
-  file = grub_gzfile_open (argv[0], 1);
+  file = grub_file_open (argv[0]);
   if (! file)
     goto fail;
 
diff --git a/loader/multiboot2.c b/loader/multiboot2.c
index 65fdea1..8d6cc34 100644
--- a/loader/multiboot2.c
+++ b/loader/multiboot2.c
@@ -28,7 +28,6 @@
 #include <grub/dl.h>
 #include <grub/mm.h>
 #include <grub/misc.h>
-#include <grub/gzio.h>
 
 static grub_addr_t entry;
 extern grub_dl_t my_mod;
@@ -323,7 +322,7 @@ grub_multiboot2 (int argc, char *argv[])
       goto fail;
     }
 
-  file = grub_gzfile_open (argv[0], 1);
+  file = grub_file_open (argv[0]);
   if (! file)
     {
       grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
@@ -423,7 +422,7 @@ grub_module2 (int argc, char *argv[])
     }
 
   /* Load module data.  */
-  file = grub_gzfile_open (argv[0], 1);
+  file = grub_file_open (argv[0]);
   if (! file)
     goto out;
 
diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c
index d6e86f1..6c9c753 100644
--- a/loader/multiboot_loader.c
+++ b/loader/multiboot_loader.c
@@ -28,7 +28,6 @@
 #include <grub/dl.h>
 #include <grub/mm.h>
 #include <grub/misc.h>
-#include <grub/gzio.h>
 
 grub_dl_t my_mod;
 
@@ -85,7 +84,7 @@ grub_rescue_cmd_multiboot_loader (int argc, char *argv[])
       goto fail;
     }
 
-  file = grub_gzfile_open (argv[0], 1);
+  file = grub_file_open (argv[0]);
   if (! file)
     {
       grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index abbea4c..fb31230 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -356,7 +356,7 @@ setup (const char *prefix, const char *dir,
       
       grub_disk_cache_invalidate_all ();
       
-      file = grub_file_open (core_path);
+      file = grub_file_ropen (core_path);
       if (file)
 	{
 	  if (grub_file_size (file) != core_size)
@@ -426,7 +426,7 @@ setup (const char *prefix, const char *dir,
     }
   
   /* Now read the core image to determine where the sectors are.  */
-  file = grub_file_open (core_path);
+  file = grub_file_ropen (core_path);
   if (! file)
     grub_util_error ("%s", grub_errmsg);
   
