2008-01-05  Bean  <bean123ch@gmail.com>

	* include/grub/file.h (grub_filehook): New structure.
	(grub_filehook_register): New function.
	(grub_filehook_unregister): New function.
	(grub_file_open_ex): New function.

	* kern/file.c (grub_filehook_list): New variable.
	(grub_filehook_register): New function.
	(grub_filehook_unregister): New function.
	(grub_file_open_ex): New function.

	* io/gzio.c (grub_filehook_open): New function.
	(grub_filehook_gzio): New variable.

	* commands/cat.c (grub_cmd_cat): Use grub_file_open_ex instead of grub_gzfile_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.
	
	* commands/ls.c (grub_ls_list_files): Use grub_file_open_ex instead of grub_file_open.

	* disk/loopback.c (grub_loopback_open): Likewise.

	* font/manager.c (add_font): Likewise.


diff --git a/commands/cat.c b/commands/cat.c
index 35b4c14..e4e4b4d 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_ex (args[0], 1);
   if (! file)
     return 0;
   
diff --git a/commands/cmp.c b/commands/cmp.c
index bb4de60..71f71df 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_ex (args[0], 1);
+  file2 = grub_file_open_ex (args[1], 1);
   if (! file1 || ! file2)
     goto cleanup;
 
diff --git a/commands/hexdump.c b/commands/hexdump.c
index d353d5e..de4355a 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_ex (args[0], 1);
       if (!file)
 	return 0;
 
diff --git a/commands/ls.c b/commands/ls.c
index e7b6302..9c3ca8c 100644
--- a/commands/ls.c
+++ b/commands/ls.c
@@ -97,7 +97,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
 
 	  /* XXX: For ext2fs symlinks are detected as files while they
 	     should be reported as directories.  */
-	  file = grub_file_open (pathname);
+	  file = grub_file_open_ex (pathname, 1);
 	  if (! file)
 	    {
 	      grub_errno = 0;
diff --git a/disk/loopback.c b/disk/loopback.c
index 31d8116..b63bbdb 100644
--- a/disk/loopback.c
+++ b/disk/loopback.c
@@ -171,7 +171,7 @@ grub_loopback_open (const char *name, grub_disk_t disk)
   if (! dev)
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
 
-  file = grub_file_open (dev->filename);
+  file = grub_file_open_ex (dev->filename, 1);
   if (! file)
     return grub_errno;
   
diff --git a/font/manager.c b/font/manager.c
index 8d5f021..c196de5 100644
--- a/font/manager.c
+++ b/font/manager.c
@@ -48,7 +48,7 @@ add_font (const char *filename)
   grub_uint32_t num, i;
   struct font *font = 0;
 
-  file = grub_file_open (filename);
+  file = grub_file_open_ex (filename, 1);
   if (! file)
     goto fail;
 
diff --git a/include/grub/file.h b/include/grub/file.h
index df2e9e4..7d2e776 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -48,10 +48,21 @@ struct grub_file
 };
 typedef struct grub_file *grub_file_t;
 
+struct grub_filehook
+{
+  grub_file_t (*open_func) (grub_file_t file);
+  struct grub_filehook *next;
+};
+typedef struct grub_filehook *grub_filehook_t;
+
+void EXPORT_FUNC(grub_filehook_register) (grub_filehook_t filehook);
+void EXPORT_FUNC(grub_filehook_unregister) (grub_filehook_t filehook);
+
 /* Get a device name from NAME.  */
 char *EXPORT_FUNC(grub_file_get_device_name) (const char *name);
 
 grub_file_t EXPORT_FUNC(grub_file_open) (const char *name);
+grub_file_t EXPORT_FUNC(grub_file_open_ex) (const char *name, int flag);
 grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, char *buf,
 					  grub_size_t len);
 grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset);
diff --git a/io/gzio.c b/io/gzio.c
index 0fada6c..e2aadcb 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_filehook_open(grub_file_t file)
+{
+  return grub_gzio_open (file, 1);
+}
+
+static struct grub_filehook grub_filehook_gzio =
+  {
+    .open_func = grub_filehook_open,
+    .next = 0
+  };
+
+GRUB_MOD_INIT(gzio)
+{
+  (void) mod;			/* To stop warning. */
+  grub_filehook_register(&grub_filehook_gzio);
+}
+
+GRUB_MOD_FINI(gzio)
+{
+  grub_filehook_unregister(&grub_filehook_gzio);
+}
diff --git a/kern/elf.c b/kern/elf.c
index b362949..3dd7ad4 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_ex (name, 1);
   if (! file)
     return 0;
 
diff --git a/kern/file.c b/kern/file.c
index adf55da..04f1d5f 100644
--- a/kern/file.c
+++ b/kern/file.c
@@ -23,6 +23,29 @@
 #include <grub/mm.h>
 #include <grub/fs.h>
 #include <grub/device.h>
+#include <grub/env.h>
+
+static grub_filehook_t grub_filehook_list;
+
+void
+grub_filehook_register (grub_filehook_t filehook)
+{
+  filehook->next = grub_filehook_list;
+  grub_filehook_list = filehook;
+}
+
+void
+grub_filehook_unregister (grub_filehook_t filehook)
+{
+  grub_filehook_t *p, q;
+
+  for (p = &grub_filehook_list, q = *p; q; p = &(q->next), q = q->next)
+    if (q == filehook)
+      {
+	*p = q->next;
+	break;
+      }
+}
 
 /* Get the device part of the filename NAME. It is enclosed by parentheses.  */
 char *
@@ -110,6 +133,34 @@ grub_file_open (const char *name)
   return 0;
 }
 
+grub_file_t
+grub_file_open_ex (const char *name, int flag)
+{
+  grub_file_t file;
+  grub_filehook_t p;
+  char *val;
+
+  file = grub_file_open (name);
+
+  if ((! file) || (! flag))
+    return file;
+
+  val = grub_env_get ("filehook");
+  if ((val) && (val[0] == '0'))
+    return file;
+
+  for (p = grub_filehook_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..c46b1a8 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_ex (argv[0], 1);
   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_ex (argv[0], 1);
   if (! file)
     goto fail;
 
diff --git a/loader/multiboot2.c b/loader/multiboot2.c
index 65fdea1..d58ea9d 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_ex (argv[0], 1);
   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_ex (argv[0], 1);
   if (! file)
     goto out;
 
diff --git a/loader/multiboot_loader.c b/loader/multiboot_loader.c
index d6e86f1..9bf2987 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_ex (argv[0], 1);
   if (! file)
     {
       grub_error (GRUB_ERR_BAD_ARGUMENT, "Couldn't open file");
