All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] FAT, UFS and mtime
@ 2009-03-01 16:25 phcoder
  2009-03-01 19:13 ` Bean
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: phcoder @ 2009-03-01 16:25 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 510 bytes --]

Hello all. It seems that gcc has trouble with -m32 when structure is 
passed as argument. So I replaced that part by a pointer. Also I made 
some improvements to ufs code to support solaris branch of ufs. I tested 
it also with freebsd and netbsd's branch and it works fine on it too.
As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a 
patch with all 3 features. If it's really necessary I can split them but 
it requires a lot of unnecessary work
-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: fs.diff --]
[-- Type: text/x-patch, Size: 63085 bytes --]

Index: conf/i386-coreboot.rmk
===================================================================
--- conf/i386-coreboot.rmk	(revision 2008)
+++ conf/i386-coreboot.rmk	(working copy)
@@ -75,6 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/completion.c normal/main.c normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
@@ -121,7 +123,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/i386-efi.rmk
===================================================================
--- conf/i386-efi.rmk	(revision 2008)
+++ conf/i386-efi.rmk	(working copy)
@@ -52,7 +52,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c 		\
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -119,10 +125,10 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
 	normal/misc.c grub_script.tab.c 				\
 	normal/script.c							\
	normal/i386/setjmp.S
 normal_mod_CFLAGS = $(COMMON_CFLAGS)
 normal_mod_ASFLAGS = $(COMMON_ASFLAGS)
 normal_mod_LDFLAGS = $(COMMON_LDFLAGS)
@@ -177,7 +183,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-ieee1275.rmk
===================================================================
--- conf/i386-ieee1275.rmk	(revision 2008)
+++ conf/i386-ieee1275.rmk	(working copy)
@@ -74,4 +74,5 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
- 	normal/completion.c normal/main.c normal/menu_text.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
 	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
@@ -111,7 +113,7 @@ pkglib_MODULES = normal.mod halt.mod reboot.mod su
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -191,7 +195,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revision 2008)
+++ conf/i386-pc.rmk	(working copy)
@@ -128,7 +128,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/color.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/color.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -209,7 +248,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c  normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -351,7 +394,7 @@ pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/powerpc-ieee1275.rmk
===================================================================
--- conf/powerpc-ieee1275.rmk	(revision 2008)
+++ conf/powerpc-ieee1275.rmk	(working copy)
@@ -56,7 +56,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/misc.c kern/parser.c kern/partition.c kern/rescue.c	\
 	kern/term.c fs/fshelp.c						\
 	normal/arg.c normal/cmdline.c normal/command.c			\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c 	\
 	normal/menu_text.c						\
 	normal/menu_entry.c normal/menu_viewer.c normal/misc.c 		\
@@ -132,7 +132,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/sparc64-ieee1275.rmk
===================================================================
--- conf/sparc64-ieee1275.rmk	(revision 2008)
+++ conf/sparc64-ieee1275.rmk	(working copy)
@@ -56,7 +56,8 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-
 #	kern/file.c kern/fs.c kern/loader.c kern/main.c kern/misc.c	\
 #	kern/parser.c kern/partition.c kern/rescue.c kern/term.c	\
 #	normal/arg.c normal/cmdline.c normal/command.c			\
-#	normal/completion.c normal/context.c normal/execute.c		\
+#	normal/completion.c normal/datetime.c normal/context.c		\
+#	normal/execute.c		\
 #	normal/function.c normal/lexer.c				\
 #	normal/main.c normal/menu.c normal/menu_entry.c			\
 #	normal/menu_text.c						\
@@ -165,7 +166,7 @@ sfs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/x86_64-efi.rmk
===================================================================
--- conf/x86_64-efi.rmk	(revision 2008)
+++ conf/x86_64-efi.rmk	(working copy)
@@ -54,7 +54,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c \
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -121,7 +122,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -179,7 +180,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: kern/fs.c
===================================================================
--- kern/fs.c	(revision 2008)
+++ kern/fs.c	(working copy)
@@ -65,10 +65,11 @@ grub_fs_t
 grub_fs_probe (grub_device_t device)
 {
   grub_fs_t p;
-  auto int dummy_func (const char *filename, int dir);
+  auto int dummy_func (const char *filename, 
+		       const struct grub_dirhook_info *info);
 
   int dummy_func (const char *filename __attribute__ ((unused)),
-		  int dir __attribute__ ((unused)))
+		  const struct grub_dirhook_info *info  __attribute__ ((unused)))
     {
       return 1;
     }
Index: kern/rescue.c
===================================================================
--- kern/rescue.c	(revision 2008)
+++ kern/rescue.c	(working copy)
@@ -176,9 +176,10 @@ grub_rescue_print_devices (const char *name)
 }
 
 static int
-grub_rescue_print_files (const char *filename, int dir)
+grub_rescue_print_files (const char *filename, 
+			  const struct grub_dirhook_info *info)
 {
-  grub_printf ("%s%s ", filename, dir ? "/" : "");
+  grub_printf ("%s%s ", filename, info->dir ? "/" : "");
   
   return 0;
 }
Index: hook/datehook.c
===================================================================
--- hook/datehook.c	(revision 2008)
+++ hook/datehook.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/env.h>
 #include <grub/misc.h>
 #include <grub/normal.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 static char *grub_datetime_names[] =
 {
Index: lib/efi/datetime.c
===================================================================
--- lib/efi/datetime.c	(revision 2008)
+++ lib/efi/datetime.c	(working copy)
@@ -21,7 +21,7 @@
 #include <grub/symbol.h>
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 grub_err_t
 grub_get_datetime (struct grub_datetime *datetime)
Index: lib/datetime.c
===================================================================
--- lib/datetime.c	(revision 2008)
+++ lib/datetime.c	(working copy)
@@ -1,49 +0,0 @@
-/* datetime.c - Module for common datetime function.  */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/lib/datetime.h>
-
-static char *grub_weekday_names[] =
-{
-  "Sunday",
-  "Monday",
-  "Tuesday",
-  "Wednesday",
-  "Thursday",
-  "Friday",
-  "Saturday",
-};
-
-int
-grub_get_weekday (struct grub_datetime *datetime)
-{
-  int a, y, m;
-
-  a = (14 - datetime->month) / 12;
-  y = datetime->year - a;
-  m = datetime->month + 12 * a - 2;
-
-  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
-}
-
-char *
-grub_get_weekday_name (struct grub_datetime *datetime)
-{
-  return grub_weekday_names[grub_get_weekday (datetime)];
-}
Index: fs/xfs.c
===================================================================
--- fs/xfs.c	(revision 2008)
+++ fs/xfs.c	(working copy)
@@ -620,7 +620,8 @@ grub_xfs_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_xfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_xfs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -633,14 +634,11 @@ grub_xfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/afs.c
===================================================================
--- fs/afs.c	(revision 2008)
+++ fs/afs.c	(working copy)
@@ -562,7 +562,8 @@ grub_afs_close (grub_file_t file)
 
 static grub_err_t
 grub_afs_dir (grub_device_t device, const char *path,
-              int (*hook) (const char *filename, int dir))
+              int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_afs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -575,14 +576,11 @@ grub_afs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ntfs.c
===================================================================
--- fs/ntfs.c	(revision 2008)
+++ fs/ntfs.c	(working copy)
@@ -864,7 +864,8 @@ fail:
 
 static grub_err_t
 grub_ntfs_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ntfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -877,14 +878,11 @@ grub_ntfs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/fat.c
===================================================================
--- fs/fat.c	(revision 2008)
+++ fs/fat.c	(working copy)
@@ -45,7 +45,8 @@
 				 | GRUB_FAT_ATTR_HIDDEN \
 				 | GRUB_FAT_ATTR_SYSTEM \
 				 | GRUB_FAT_ATTR_DIRECTORY \
-				 | GRUB_FAT_ATTR_ARCHIVE)
+				 | GRUB_FAT_ATTR_ARCHIVE \
+				 | GRUB_FAT_ATTR_VOLUME_ID)
 
 struct grub_fat_bpb
 {
@@ -467,51 +468,21 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
   return ret;
 }
 
-/* Find the underlying directory or file in PATH and return the
-   next path. If there is no next path or an error occurs, return NULL.
-   If HOOK is specified, call it with each file name.  */
-static char *
-grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
-		   const char *path,
-		   int (*hook) (const char *filename, int dir))
+static grub_err_t
+grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
+		      int (*hook) (const char *filename, 
+				   struct grub_fat_dir_entry *dir))
 {
   struct grub_fat_dir_entry dir;
-  char *dirname, *dirp;
   char *filename, *filep = 0;
   grub_uint16_t *unibuf;
   int slot = -1, slots = -1;
   int checksum = -1;
   grub_ssize_t offset = -sizeof(dir);
-  int call_hook;
   
   if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
-    {
-      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
-      return 0;
-    }
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
   
-  /* Extract a directory name.  */
-  while (*path == '/')
-    path++;
-
-  dirp = grub_strchr (path, '/');
-  if (dirp)
-    {
-      unsigned len = dirp - path;
-      
-      dirname = grub_malloc (len + 1);
-      if (! dirname)
-	return 0;
-
-      grub_memcpy (dirname, path, len);
-      dirname[len] = '\0';
-    }
-  else
-    /* This is actually a file.  */
-    dirname = grub_strdup (path);
-
-  call_hook = (! dirp && hook);
-  
   /* Allocate space enough to hold a long name.  */
   filename = grub_malloc (0x40 * 13 * 4 + 1);
   unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
@@ -519,7 +490,6 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
     {
       grub_free (filename);
       grub_free (unibuf);
-      grub_free (dirname);
       return 0;
     }
       
@@ -533,15 +503,8 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
       /* Read a directory entry.  */
       if ((grub_fat_read_data (disk, data, 0,
 			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno == GRUB_ERR_NONE && ! call_hook)
-	    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
-
-	  break;
-	}
-
+	   != sizeof (dir) || dir.name[0] == 0))
+	break;
       /* Handle long name entries.  */
       if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
 	{
@@ -594,22 +557,11 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 	      *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
 				   slots * 13) = '\0';
 	      
-	      if (*dirname == '\0' && call_hook)
-		{
-		  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-		    break;
-		  
-		  checksum = -1;
-		  continue;
-		}
-
-	      if (grub_strcmp (dirname, filename) == 0)
-		{
-		  if (call_hook)
-		    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
-		  
-		  break;
-		}
+	      if (hook (filename, &dir))
+		break;
+	      
+	      checksum = -1;
+	      continue;
 	    }
 
 	  checksum = -1;
@@ -617,49 +569,122 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 
       /* Convert the 8.3 file name.  */
       filep = filename;
-      
-      for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*filep++ = grub_tolower (dir.name[i]);
-      
-      *filep = '.';
-      
-      for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*++filep = grub_tolower (dir.name[i]);
-
-      if (*filep != '.')
-	filep++;
-      
-      *filep = '\0';
-
-      if (*dirname == '\0' && call_hook)
+      if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
 	{
-	  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-	    break;
+	  for (i = 0; i < sizeof (dir.name) && dir.name[i] 
+		 && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = dir.name[i];
 	}
-      else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
+      else
 	{
-	  if (call_hook)
-	    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
+	  for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = grub_tolower (dir.name[i]);
+      
+	  *filep = '.';
+	  
+	  for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *++filep = grub_tolower (dir.name[i]);
 
-	  break;
+	  if (*filep != '.')
+	    filep++;
 	}
+      *filep = '\0';
+
+      if (hook (filename, &dir))
+	break;
     }
 
   grub_free (filename);
+
+  return grub_errno;
+}
+
+
+/* Find the underlying directory or file in PATH and return the
+   next path. If there is no next path or an error occurs, return NULL.
+   If HOOK is specified, call it with each file name.  */
+static char *
+grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
+		   const char *path,
+		   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
+{
+  char *dirname, *dirp;
+  int call_hook;
+  int found = 0;
+
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    struct grub_dirhook_info info;
+    grub_memset (&info, 0, sizeof (info));
+
+    info.dir = !!(dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+    info.case_insensitive = 1;
+
+    if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
+      return 0;
+    if (*dirname == '\0' && call_hook)
+      return hook (filename, &info);
+
+    if (grub_strcasecmp (dirname, filename) == 0)
+      {
+	found = 1;
+	data->attr = dir->attr;
+	data->file_size = grub_le_to_cpu32 (dir->file_size);
+	data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
+			      | grub_le_to_cpu16 (dir->first_cluster_low));
+	data->cur_cluster_num = ~0U;
+
+	if (call_hook)
+	  hook (filename, &info);
+	    
+	return 1;
+      }
+    return 0;
+  }
+  
+  if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
+      return 0;
+    }
+  
+  /* Extract a directory name.  */
+  while (*path == '/')
+    path++;
+
+  dirp = grub_strchr (path, '/');
+  if (dirp)
+    {
+      unsigned len = dirp - path;
+      
+      dirname = grub_malloc (len + 1);
+      if (! dirname)
+	return 0;
+
+      grub_memcpy (dirname, path, len);
+      dirname[len] = '\0';
+    }
+  else
+    /* This is actually a file.  */
+    dirname = grub_strdup (path);
+
+  call_hook = (! dirp && hook);
+  
+  grub_fat_iterate_dir (disk, data, iter_hook);
+  if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
+    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
   grub_free (dirname);
 
-  data->attr = dir.attr;
-  data->file_size = grub_le_to_cpu32 (dir.file_size);
-  data->file_cluster = ((grub_le_to_cpu16 (dir.first_cluster_high) << 16)
-			| grub_le_to_cpu16 (dir.first_cluster_low));
-  data->cur_cluster_num = ~0U;
-  
-  return dirp;
+  return found ? dirp : 0;
 }
 
 static grub_err_t
 grub_fat_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_fat_data *data = 0;
   grub_disk_t disk = device->disk;
@@ -773,8 +798,17 @@ grub_fat_label (grub_device_t device, char **label
 {
   struct grub_fat_data *data;
   grub_disk_t disk = device->disk;
-  grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
 
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
+      {
+	*label = grub_strdup (filename);
+	return 1;
+      }
+    return 0;
+  }
 
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
@@ -790,37 +824,10 @@ grub_fat_label (grub_device_t device, char **label
       return 0;
     }
 
-  while (1)
-    {
-      struct grub_fat_dir_entry dir;
-
-      /* Adjust the offset.  */
-      offset += sizeof (dir);
-      
-      /* Read a directory entry.  */
-      if ((grub_fat_read_data (disk, data, 0,
-			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno != GRUB_ERR_NONE)
-	    goto fail;
-	  else
-	    {
-	      *label = 0;
-	      return GRUB_ERR_NONE;
-	    }
-	}
-
-      if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
-	{
-	  *label = grub_strndup ((char *) dir.name, 11);
-	  return GRUB_ERR_NONE;
-	}
-    }
-
   *label = 0;
   
+  grub_fat_iterate_dir (disk, data, iter_hook);
+
  fail:
 
 #ifndef GRUB_UTIL
Index: fs/udf.c
===================================================================
--- fs/udf.c	(revision 2008)
+++ fs/udf.c	(working copy)
@@ -768,7 +768,8 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
 
 static grub_err_t
 grub_udf_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_udf_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -782,14 +783,11 @@ grub_udf_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/iso9660.c
===================================================================
--- fs/iso9660.c	(revision 2008)
+++ fs/iso9660.c	(working copy)
@@ -666,7 +666,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
 \f
 static grub_err_t
 grub_iso9660_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_iso9660_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -680,14 +681,11 @@ grub_iso9660_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/affs.c
===================================================================
--- fs/affs.c	(revision 2008)
+++ fs/affs.c	(working copy)
@@ -456,7 +456,8 @@ grub_affs_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_affs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_affs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -469,14 +470,11 @@ grub_affs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/hfs.c
===================================================================
--- fs/hfs.c	(revision 2008)
+++ fs/hfs.c	(working copy)
@@ -721,7 +721,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, con
 \f
 static grub_err_t
 grub_hfs_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename,
+			       const struct grub_dirhook_info *info))
 {
   int inode;
 
@@ -732,13 +733,17 @@ grub_hfs_dir (grub_device_t device, const char *pa
       char fname[32] = { 0 };
       char *filetype = rec->data;
       struct grub_hfs_catalog_key *ckey = rec->key;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       grub_strncpy (fname, (char *) (ckey->str), ckey->strlen);
       
-      if (*filetype == GRUB_HFS_FILETYPE_DIR)
-	return hook (fname, 1);
-      else if (*filetype == GRUB_HFS_FILETYPE_FILE)
-	return hook (fname, 0);
+      if (*filetype == GRUB_HFS_FILETYPE_DIR 
+	  || *filetype == GRUB_HFS_FILETYPE_FILE)
+	{
+	  info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR);
+	  return hook (fname, &info);
+	}
       return 0;
     }
   
Index: fs/reiserfs.c
===================================================================
--- fs/reiserfs.c	(revision 2008)
+++ fs/reiserfs.c	(working copy)
@@ -1266,7 +1266,8 @@ grub_reiserfs_close (grub_file_t file)
 /* Call HOOK with each file under DIR.  */
 static grub_err_t
 grub_reiserfs_dir (grub_device_t device, const char *path,
-                   int (*hook) (const char *filename, int dir))
+                   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
 {
   struct grub_reiserfs_data *data = 0;
   struct grub_fshelp_node root, *found;
@@ -1280,12 +1281,11 @@ grub_reiserfs_dir (grub_device_t device, const cha
                                 enum grub_fshelp_filetype filetype,
                                 grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-        return hook (filename, 1);
-      else
-        return hook (filename, 0);
+      return hook (filename, &info);
     }
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
Index: fs/jfs.c
===================================================================
--- fs/jfs.c	(revision 2008)
+++ fs/jfs.c	(working copy)
@@ -728,7 +728,8 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *dat
 
 static grub_err_t
 grub_jfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_jfs_data *data = 0;
   struct grub_jfs_diropen *diro = 0;
@@ -752,14 +753,15 @@ grub_jfs_dir (grub_device_t device, const char *pa
   while (grub_jfs_getent (diro) != GRUB_ERR_OUT_OF_RANGE)
     {
       struct grub_jfs_inode inode;
-      int isdir;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       if (grub_jfs_read_inode (data, diro->ino, &inode))
 	goto fail;
       
-      isdir = (grub_le_to_cpu32 (inode.mode)
-	       & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
-      if (hook (diro->name, isdir))
+      info.dir = (grub_le_to_cpu32 (inode.mode)
+		  & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
+      if (hook (diro->name, &info))
 	goto fail;
     }
   
Index: fs/ext2.c
===================================================================
--- fs/ext2.c	(revision 2008)
+++ fs/ext2.c	(working copy)
@@ -788,7 +790,8 @@ grub_ext2_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_ext2_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ext2_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -801,14 +804,24 @@ grub_ext2_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      if (! node->inode_read)
+	{
+	  grub_ext2_read_inode (data, node->ino, &node->inode);
+	  if (!grub_errno)
+	    node->inode_read = 1;
+	  grub_errno = GRUB_ERR_NONE;
+	}
+      if (node->inode_read)
+	{
+	  info.mtimeset = 1;
+	  info.mtime = grub_le_to_cpu32 (node->inode.mtime);
+	}
+
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -895,6 +908,34 @@ grub_ext2_uuid (grub_device_t device, char **uuid)
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ext2_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ext2_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_le_to_cpu32 (data->sblock.utime);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_ext2_fs =
   {
@@ -905,6 +946,7 @@ static struct grub_fs grub_ext2_fs =
     .close = grub_ext2_close,
     .label = grub_ext2_label,
     .uuid = grub_ext2_uuid,
+    .mtime = grub_ext2_mtime,
     .next = 0
   };
 
Index: fs/hfsplus.c
===================================================================
--- fs/hfsplus.c	(revision 2008)
+++ fs/hfsplus.c	(working copy)
@@ -57,9 +57,11 @@ struct grub_hfsplus_volheader
   grub_uint16_t magic;
   grub_uint16_t version;
   grub_uint32_t attributes;
-  grub_uint8_t unused[32];
+  grub_uint8_t unused1[12];
+  grub_uint32_t utime;
+  grub_uint8_t unused2[16];
   grub_uint32_t blksize;
-  grub_uint8_t unused2[68];
+  grub_uint8_t unused3[68];
   struct grub_hfsplus_forkdata allocations_file;
   struct grub_hfsplus_forkdata extents_file;
   struct grub_hfsplus_forkdata catalog_file;
@@ -133,9 +135,11 @@ struct grub_hfsplus_catfile
   grub_uint16_t flags;
   grub_uint32_t reserved;
   grub_uint32_t fileid;
-  grub_uint8_t unused1[30];
+  grub_uint8_t unused1[4];
+  grub_uint32_t mtime;
+  grub_uint8_t unused2[22];
   grub_uint16_t mode;
-  grub_uint8_t unused2[44];
+  grub_uint8_t unused3[44];
   struct grub_hfsplus_forkdata data;
   struct grub_hfsplus_forkdata resource;
 } __attribute__ ((packed));
@@ -190,6 +194,7 @@ struct grub_fshelp_node
   struct grub_hfsplus_extent extents[8];
   grub_uint64_t size;
   grub_uint32_t fileid;
+  grub_int32_t mtime;
 };
 
 struct grub_hfsplus_btree
@@ -780,6 +786,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
 	  
 	  grub_memcpy (node->extents, fileinfo->data.extents,
 		       sizeof (node->extents));
+	  node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
 	  node->size = grub_be_to_cpu64 (fileinfo->data.size);
 	  node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
 
@@ -885,7 +892,8 @@ grub_hfsplus_read (grub_file_t file, char *buf, gr
 
 static grub_err_t
 grub_hfsplus_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_hfsplus_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -898,14 +906,14 @@ grub_hfsplus_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      info.mtimeset = 1;
+      info.mtime = node->mtime;
+      info.case_insensitive = !!(filetype & GRUB_FSHELP_CASE_INSENSITIVE);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -949,6 +957,34 @@ grub_hfsplus_label (grub_device_t device __attribu
 		     "partition is not implemented");
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_hfsplus_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_hfsplus_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_hfsplus_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_be_to_cpu32 (data->volheader.utime) - 2082844800;
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_hfsplus_fs =
   {
@@ -958,6 +994,7 @@ static struct grub_fs grub_hfsplus_fs =
     .read = grub_hfsplus_read,
     .close = grub_hfsplus_close,
     .label = grub_hfsplus_label,
+    .mtime = grub_hfsplus_mtime,
     .next = 0
   };
 
Index: fs/minix.c
===================================================================
--- fs/minix.c	(revision 2008)
+++ fs/minix.c	(working copy)
@@ -461,7 +461,8 @@ grub_minix_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_minix_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_minix_data *data = 0;
   struct grub_minix_sblock *sblock;
@@ -492,6 +493,9 @@ grub_minix_dir (grub_device_t device, const char *
       grub_uint16_t ino;
       char filename[data->filename_size + 1];
       int dirino = data->ino;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+
       
       if (grub_minix_read_file (data, 0, pos, sizeof (ino),
 				(char *) &ino) < 0)
@@ -506,8 +510,9 @@ grub_minix_dir (grub_device_t device, const char *
       /* The filetype is not stored in the dirent.  Read the inode to
 	 find out the filetype.  This *REALLY* sucks.  */
       grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
-      if (hook (filename, ((GRUB_MINIX_INODE_MODE (data) 
-			    & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR)) ? 1 : 0)
+      info.dir = ((GRUB_MINIX_INODE_MODE (data) 
+		   & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
+      if (hook (filename, &info) ? 1 : 0)
 	break;
       
       /* Load the old inode back in.  */
Index: fs/cpio.c
===================================================================
--- fs/cpio.c	(revision 2008)
+++ fs/cpio.c	(working copy)
@@ -183,7 +183,8 @@ fail:
 
 static grub_err_t
 grub_cpio_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_cpio_data *data;
   grub_uint32_t ofs;
@@ -227,7 +228,11 @@ grub_cpio_dir (grub_device_t device, const char *p
 
 	  if ((!prev) || (grub_strcmp (prev, name) != 0))
 	    {
-	      hook (name + len, p != NULL);
+	      struct grub_dirhook_info info;
+	      grub_memset (&info, 0, sizeof (info));
+	      info.dir = (p != NULL);
+
+	      hook (name + len, &info);
 	      if (prev)
 		grub_free (prev);
 	      prev = name;
Index: fs/sfs.c
===================================================================
--- fs/sfs.c	(revision 2008)
+++ fs/sfs.c	(working copy)
@@ -519,7 +519,8 @@ grub_sfs_read (grub_file_t file, char *buf, grub_s
 
 static grub_err_t
 grub_sfs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_sfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -532,14 +533,11 @@ grub_sfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ufs.c
===================================================================
--- fs/ufs.c	(revision 2008)
+++ fs/ufs.c	(working copy)
@@ -36,7 +36,10 @@
 #define GRUB_UFS_DIRBLKS	12
 #define GRUB_UFS_INDIRBLKS	3
 
-#define GRUB_UFS_ATTR_DIR	040000
+#define GRUB_UFS_ATTR_TYPE      0160000
+#define GRUB_UFS_ATTR_FILE	0100000
+#define GRUB_UFS_ATTR_DIR	0040000
+#define GRUB_UFS_ATTR_LNK       0120000
 
 #define GRUB_UFS_VOLNAME_LEN	32
 
@@ -51,6 +54,8 @@
                            grub_le_to_cpu##bits1 (data->inode.field) : \
                            grub_le_to_cpu##bits2 (data->inode2.field))
 #define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
+#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
+
 #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
 #define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
@@ -71,29 +76,35 @@ struct grub_ufs_sblock
   
   /* The start of the cylinder group.  */
   grub_uint32_t cylg_offset;
+  grub_uint8_t unused3[4];
+
+  grub_uint32_t mtime;
+  grub_uint8_t unused4[12];
   
-  grub_uint8_t unused3[20];
-  
   /* The size of a block in bytes.  */
   grub_int32_t bsize;
-  grub_uint8_t unused4[48];
+  grub_uint8_t unused5[48];
   
   /* The size of filesystem blocks to disk blocks.  */
   grub_uint32_t log2_blksz;
-  grub_uint8_t unused5[80];
+  grub_uint8_t unused6[80];
   
   /* Inodes stored per cylinder group.  */
   grub_uint32_t ino_per_group;
   
   /* The frags per cylinder group.  */
   grub_uint32_t frags_per_group;
+  grub_uint8_t unused7[19];
+  grub_uint8_t flags;
   
-  grub_uint8_t unused7[488];
+  grub_uint8_t unused8[468];
 
   /* Volume name for UFS2.  */
   grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
+  grub_uint8_t unused9[232];
 
-  grub_uint8_t unused8[660];
+  grub_uint64_t mtime2;
+  grub_uint8_t unused10[420];
   
   /* Magic value to check if this is really a UFS filesystem.  */
   grub_uint32_t magic;
@@ -124,7 +135,7 @@ struct grub_ufs_inode
   grub_uint32_t gen;
   grub_uint32_t unused;
   grub_uint8_t pad[12];
-};
+} __attribute__ ((packed));
 
 /* UFS inode.  */
 struct grub_ufs2_inode
@@ -160,16 +171,23 @@ struct grub_ufs2_inode
   };
 
   grub_uint8_t unused[24];
-};
+} __attribute__ ((packed));
 
 /* Directory entry.  */
 struct grub_ufs_dirent
 {
   grub_uint32_t ino;
   grub_uint16_t direntlen;
-  grub_uint8_t filetype;
-  grub_uint8_t namelen;
-};
+  union
+  {
+    grub_uint16_t namelen;
+    struct
+    {
+      grub_uint8_t filetype_bsd;
+      grub_uint8_t namelen_bsd;      
+    };
+  };
+} __attribute__ ((packed));
 
 /* Information about a "mounted" ufs filesystem.  */
 struct grub_ufs_data
@@ -225,24 +243,24 @@ grub_ufs_get_file_block (struct grub_ufs_data *dat
       return (data->ufs_type == UFS1) ? indir[blk] : indir[blk << 1];
     }
   blk -= indirsz;
-  
+
   /* Double indirect block.  */
-  if (blk < UFS_BLKSZ (sblock) / indirsz)
+  if (blk < indirsz * indirsz)
     {
       grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
       
       grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       grub_disk_read (data->disk,
-      		      (data->ufs_type == UFS1) ?
-		      indir[blk / indirsz] : indir [(blk / indirsz) << 1],
+      		      ((data->ufs_type == UFS1) ?
+		      indir[blk / indirsz] : indir [(blk / indirsz) << 1]) 
+		      << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       
       return (data->ufs_type == UFS1) ?
 	     indir[blk % indirsz] : indir[(blk % indirsz) << 1];
     }
 
-
   grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 	      "ufs does not support triple indirect blocks");
   return 0;
@@ -320,7 +338,7 @@ grub_ufs_read_file (struct grub_ufs_data *data,
 /* Read inode INO from the mounted filesystem described by DATA.  This
    inode is used by default now.  */
 static grub_err_t
-grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
+grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
 {
   struct grub_ufs_sblock *sblock = &data->sblock;
   
@@ -335,8 +353,12 @@ static grub_err_t
   
   if (data->ufs_type == UFS1)
     {
-      struct grub_ufs_inode *inode = &data->inode;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -347,8 +369,12 @@ static grub_err_t
     }
   else
     {
-      struct grub_ufs2_inode *inode = &data->inode2;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode2;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -358,7 +384,6 @@ static grub_err_t
 		      (char *) inode);
     }
   
-  data->ino = ino;
   return grub_errno;
 }
 
@@ -372,9 +397,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
   
   if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
     return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
-  
-  if (INODE_SIZE (data) < (GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS
-			  * INODE_BLKSZ (data)))
+
+  if (INODE_NBLOCKS (data) == 0)
     grub_strcpy (symlink, (char *) INODE (data, symlink));
   else
     {
@@ -390,7 +414,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
     ino = GRUB_UFS_INODE;
   
   /* Now load in the old inode.  */
-  if (grub_ufs_read_inode (data, ino))
+  if (grub_ufs_read_inode (data, ino, 0))
     return grub_errno;
   
   grub_ufs_find_file (data, symlink);
@@ -433,29 +457,34 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
   do
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_strlen (name) == 0)
 	return GRUB_ERR_NONE;
       
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	return grub_errno;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
 
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  return grub_errno;
 	
-	filename[dirent.namelen] = '\0';
+	filename[namelen] = '\0';
 	
 	if (!grub_strcmp (name, filename))
 	  {
 	    dirino = data->ino;
-	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino));
-	    
-	    if (dirent.filetype == GRUB_UFS_FILETYPE_LNK)
+	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino), 0);
+
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
+		== GRUB_UFS_ATTR_LNK)
 	      {
 		grub_ufs_lookup_symlink (data, dirino);
 		if (grub_errno)
@@ -475,7 +504,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
 		next++;
 	      }
 	    
-	    if (!(dirent.filetype & GRUB_UFS_FILETYPE_DIR))
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 	      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 	    
 	    continue;
@@ -544,7 +573,8 @@ grub_ufs_mount (grub_disk_t disk)
 
 static grub_err_t
 grub_ufs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ufs_data *data;
   struct grub_ufs_sblock *sblock;
@@ -554,7 +584,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, GRUB_UFS_INODE);
+  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
   if (grub_errno)
     return grub_errno;
   
@@ -570,7 +600,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (grub_errno)
     goto fail;  
   
-  if (!(INODE_MODE (data) & GRUB_UFS_ATTR_DIR))
+  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
     {
       grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
       goto fail;
@@ -579,20 +609,45 @@ grub_ufs_dir (grub_device_t device, const char *pa
   while (pos < INODE_SIZE (data))
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	break;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
+	struct grub_dirhook_info info;
+	grub_memset (&info, 0, sizeof (info));
 	
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  break;
 	
-	filename[dirent.namelen] = '\0';
-	if (hook (filename, dirent.filetype == GRUB_UFS_FILETYPE_DIR))
+	filename[namelen] = '\0';
+	if (data->ufs_type == UFS1)
+	  {
+	    struct grub_ufs_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+	else
+	  {
+	    struct grub_ufs2_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+
+	if (hook (filename, &info))
 	  break;
       }
       
@@ -615,7 +670,7 @@ grub_ufs_open (struct grub_file *file, const char
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, 2);
+  grub_ufs_read_inode (data, 2, 0);
   if (grub_errno)
     {
       grub_free (data);
@@ -688,6 +743,34 @@ grub_ufs_label (grub_device_t device, char **label
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ufs_data *data = 0;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ufs_mount (device->disk);
+  if (!data)
+    *tm = 0;
+  else if (data->ufs_type == UFS1)
+    *tm = grub_le_to_cpu32 (data->sblock.mtime);
+  else
+    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+}
+
+
 \f
 static struct grub_fs grub_ufs_fs =
   {
@@ -697,6 +780,7 @@ static struct grub_fs grub_ufs_fs =
     .read = grub_ufs_read,
     .close = grub_ufs_close,
     .label = grub_ufs_label,
+    .mtime = grub_ufs_mtime,
     .next = 0
   };
 
Index: include/grub/fs.h
===================================================================
--- include/grub/fs.h	(revision 2008)
+++ include/grub/fs.h	(working copy)
@@ -27,6 +27,14 @@
 /* Forward declaration is required, because of mutual reference.  */
 struct grub_file;
 
+struct grub_dirhook_info
+{
+  int dir:1;
+  int mtimeset:1;
+  int case_insensitive:1;
+  grub_int32_t mtime;
+};
+
 /* Filesystem descriptor.  */
 struct grub_fs
 {
@@ -35,7 +43,8 @@ struct grub_fs
 
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
-		     int (*hook) (const char *filename, int dir));
+		     int (*hook) (const char *filename, 
+				  const struct grub_dirhook_info *info));
   
   /* Open a file named NAME and initialize FILE.  */
   grub_err_t (*open) (struct grub_file *file, const char *name);
@@ -56,6 +65,9 @@ struct grub_fs
      caller.  */
   grub_err_t (*uuid) (grub_device_t device, char **uuid);
 
+  /* Get writing time of filesystem. */
+  grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf);
+
   /* The next filesystem.  */
   struct grub_fs *next;
 };
Index: include/grub/fshelp.h
===================================================================
--- include/grub/fshelp.h	(revision 2008)
+++ include/grub/fshelp.h	(working copy)
@@ -27,6 +27,8 @@
 typedef struct grub_fshelp_node *grub_fshelp_node_t;
 
 #define GRUB_FSHELP_CASE_INSENSITIVE	0x100
+#define GRUB_FSHELP_TYPE_MASK	0xff
+#define GRUB_FSHELP_FLAGS_MASK	0x100
 
 enum grub_fshelp_filetype
   {
Index: normal/completion.c
===================================================================
--- normal/completion.c	(revision 2008)
+++ normal/completion.c	(working copy)
@@ -123,9 +123,9 @@ iterate_partition (grub_disk_t disk, const grub_pa
 }
 
 static int
-iterate_dir (const char *filename, int dir)
+iterate_dir (const char *filename, const struct grub_dirhook_info *info)
 {
-  if (! dir)
+  if (! info->dir)
     {
       const char *prefix;
       if (cmdline_state == GRUB_PARSER_STATE_DQUOTE)
Index: normal/datetime.c
===================================================================
--- normal/datetime.c	(revision 1989)
+++ normal/datetime.c	(working copy)
@@ -17,7 +17,7 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 static char *grub_weekday_names[] =
 {
@@ -47,3 +47,54 @@ grub_get_weekday_name (struct grub_datetime *datet
 {
   return grub_weekday_names[grub_get_weekday (datetime)];
 }
+
+#define SECPERMIN 60
+#define SECPERHOUR (60*SECPERMIN)
+#define SECPERDAY (24*SECPERHOUR)
+#define SECPERYEAR (365*SECPERDAY)
+#define SECPER4YEARS (4*SECPERYEAR+SECPERDAY)
+
+
+void
+grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime)
+{
+  int i;
+  int div;
+  grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 
+  /* In the period of validity of unixtime all years divisible by 4 
+     are bissextile*/
+  /* Convenience: let's have 3 consecutive non-bissextile years 
+     at the begining of the epoch. So count from 1973 instead of 1970 */
+  nix -= 3*SECPERYEAR + SECPERDAY;
+  /* Transform C divisions and modulos to mathematical ones */
+  div = nix / SECPER4YEARS;
+  if (nix < 0)
+    div--;
+  datetime->year = 1973 + 4 * div;
+  nix -= div * SECPER4YEARS;
+
+  /* On 31st december of bissextile years 365 days from the begining 
+     of the year elapsed but year isn't finished yet*/
+  if (nix / SECPERYEAR == 4)
+    {
+      datetime->year += 3;
+      nix -= 3*SECPERYEAR;
+    }
+  else
+    {
+      datetime->year += nix / SECPERYEAR;
+      nix %= SECPERYEAR;
+    }
+  for (i = 0; i < 12 
+	 && nix >= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+				    ? 29 : months[i]))*SECPERDAY; i++)
+    nix -= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+			    ? 29 : months[i]))*SECPERDAY;
+  datetime->month = i + 1; 
+  datetime->day = 1 + (nix / SECPERDAY);
+  nix %= SECPERDAY;
+  datetime->hour = (nix / SECPERHOUR);  
+  nix %= SECPERHOUR;
+  datetime->minute = nix / SECPERMIN;
+  datetime->second = nix % SECPERMIN;
+}

Property changes on: normal/datetime.c
___________________________________________________________________
Added: svn:mergeinfo

Index: commands/date.c
===================================================================
--- commands/date.c	(revision 2008)
+++ commands/date.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/arg.h>
 #include <grub/err.h>
 #include <grub/misc.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 #define GRUB_DATETIME_SET_YEAR		1
 #define GRUB_DATETIME_SET_MONTH		2
Index: commands/ls.c
===================================================================
--- commands/ls.c	(revision 2008)
+++ commands/ls.c	(working copy)
@@ -29,6 +29,7 @@
 #include <grub/term.h>
 #include <grub/partition.h>
 #include <grub/file.h>
+#include <grub/datetime.h>
 
 static const struct grub_arg_option options[] =
   {
@@ -68,25 +69,29 @@ grub_ls_list_files (char *dirname, int longlist, i
   grub_fs_t fs;
   const char *path;
   grub_device_t dev;
-  auto int print_files (const char *filename, int dir);
-  auto int print_files_long (const char *filename, int dir);
+
+  auto int print_files (const char *filename, 
+			const struct grub_dirhook_info *info);
+  auto int print_files_long (const char *filename, 
+			     const struct grub_dirhook_info *info);
   
-  int print_files (const char *filename, int dir)
+  int print_files (const char *filename, const struct grub_dirhook_info *info)
     {
       if (all || filename[0] != '.')
-	grub_printf ("%s%s ", filename, dir ? "/" : "");
+	grub_printf ("%s%s ", filename, info->dir ? "/" : "");
       
       return 0;
     }
      
-  int print_files_long (const char *filename, int dir)
+  int print_files_long (const char *filename, 
+			const struct grub_dirhook_info *info)
     {
       char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1];
 
       if ((! all) && (filename[0] == '.'))
 	return 0;
 
-      if (! dir)
+      if (! info->dir)
 	{
 	  grub_file_t file;
 	  
@@ -138,7 +143,23 @@ grub_ls_list_files (char *dirname, int longlist, i
       else
 	grub_printf ("%-12s", "DIR");
 
-      grub_printf ("%s%s\n", filename, dir ? "/" : "");
+      if (info->mtimeset)
+	{
+	  struct grub_datetime datetime;
+	  grub_unixtime2datetime (info->mtime, &datetime);
+	  if (human)
+	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
+			 datetime.year, datetime.month, datetime.day,
+			 datetime.hour, datetime.minute, 
+			 datetime.second,
+			 grub_get_weekday_name (&datetime));
+	  else
+	    grub_printf (" %04d%02d%02d%02d%02d%02d ",
+			 datetime.year, datetime.month, 
+			 datetime.day, datetime.hour, 
+			 datetime.minute, datetime.second);
+	}
+      grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
 
       return 0;
     }
@@ -181,7 +202,7 @@ grub_ls_list_files (char *dirname, int longlist, i
 	  /* PATH might be a regular file.  */
 	  char *p;
 	  grub_file_t file;
-
+	  struct grub_dirhook_info info;
 	  grub_errno = 0;
 	  
 	  file = grub_file_open (dirname);
@@ -196,10 +217,11 @@ grub_ls_list_files (char *dirname, int longlist, i
 	    goto fail;
 
 	  all = 1;
+	  grub_memset (&info, 0, sizeof (info));
 	  if (longlist)
-	    print_files_long (p, 0);
+	    print_files_long (p, &info);
 	  else
-	    print_files (p, 0);
+	    print_files (p, &info);
 
 	  grub_free (dirname);
 	}
Index: util/hostfs.c
===================================================================
--- util/hostfs.c	(revision 2008)
+++ util/hostfs.c	(working copy)
@@ -16,7 +16,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
-
+#define _BSD_SOURCE
 #include <grub/fs.h>
 #include <grub/file.h>
 #include <grub/disk.h>
@@ -57,7 +57,8 @@ is_dir (const char *path, const char *name)
 
 static grub_err_t
 grub_hostfs_dir (grub_device_t device, const char *path, 
-		 int (*hook) (const char *filename, int dir))
+		 int (*hook) (const char *filename, 
+			      const struct grub_dirhook_info *info))
 {
   DIR *dir;
 
@@ -73,16 +74,20 @@ grub_hostfs_dir (grub_device_t device, const char
   while (1)
     {
       struct dirent *de;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
 
       de = readdir (dir);
       if (! de)
 	break;
 
 #ifdef DT_DIR
-      hook (de->d_name, de->d_type == DT_DIR);
+      info.dir = (de->d_type == DT_DIR);
 #else
-      hook (de->d_name, is_dir (path, de->d_name));
+      info.dir = !!is_dir (path, de->d_name);
 #endif
+      hook (de->d_name, &info);
+
     }
 
   closedir (dir);
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2008)
+++ ChangeLog	(working copy)
@@ -1,3 +1,77 @@
+2009-03-01  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	UFS improvements
+
+	* fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
+	(GRUB_UFS_ATTR_FILE): likewise
+	(GRUB_UFS_ATTR_LNK): likewise
+	(GRUB_UFS_BSD_DIRENT): likewise
+	(struct grub_ufs_sblock): new fields mtime and flags
+	(struct grub_ufs_dirent): added fields for non-BSD dirents
+	(grub_ufs_get_file_block): fixed double indirect handling
+	(grub_ufs_read_inode): new parameter to read inode to a separate buffer
+	all users updated
+	(grub_ufs_find_file): support for non-BSD dirents
+	(grub_ufs_dir): likewise and mtime support
+	(grub_ufs_mtime): new function
+
+2009-03-01  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Support for mtime and further expandability of dir command
+
+	* include/grub/lib/datetime.h: moved to ...
+	* include/grub/datetime.h: ... moved here and added 
+	declaration of grub_unixtime2datetime. All users updated
+	* include/grub/fs.h: new syntax for dir and mtime functionin 
+	struct grub_fs 
+	* include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
+	and GRUB_FSHELP_FLAGS_MASK
+	* commands/ls.c (grub_ls_list_files): Write mtime in long format
+	* fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
+	(grub_ext2_mtime): new function
+	* fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply mtime
+	(grub_hfsplus_mtime): new function
+	* fs/affs.c (grub_affs_dir): use new dir syntax
+	* fs/afs.c (grub_afs_dir): likewise
+	* fs/cpio.c (grub_cpio_dir): likewise
+	* fs/fat.c (grub_fat_find_dir): likewise
+	* fs/hfs.c (grub_hfs_dir): likewise
+	* fs/iso9660.c (grub_iso9660_dir): likewise
+	* fs/jfs.c (grub_jfs_dir): likewise
+	* fs/minix.c (grub_minix_dir): likewise
+	* fs/ntfs.c (grub_ntfs_dir): likewise
+	* fs/reiserfs.c (grub_reiserfs_dir): likewise
+	* fs/sfs.c (grub_sfs_dir): likewise
+	* fs/xfs.c (grub_xfs_dir): likewise
+	* fs/ufs.c (grub_ufs_dir): likewise
+	* util/hostfs.c (grub_hostfs_dir): likewise
+	* lib/datetime.c: moved to ...
+	* normal/datetime.c: ... moved here
+	(grub_unixtime2datetime): new function
+	* kern/rescue.c (grub_rescue_print_files): use new dir syntax
+	* normal/completition.c (iterate_dir): use new dir syntax
+	* normal/misc.c (grub_normal_print_device_info): tell the 
+	last modification time of a volume
+	* kern/fs.c (grub_fs_probe): updated dummy function to use new syntax 
+	* conf/common.rmk: added lib/datetime.c to ls.mod
+	* conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu 
+	and normal.mod. Removed lib/datetime.c from datetime.mod
+	* conf/i386-efi.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise	
+	* conf/i386-pc.rmk: likewise
+	* conf/powerpc-ieee1275.rmk: likewise
+	* conf/sparc64-ieee1275.rmk: likewise	
+	* conf/x86_64-efi.rmk: likewise	
+	
+2009-02-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Trim trailing spaces in FAT label and support mtools-like labels
+	
+	* fs/fat.c (grub_fat_iterate_dir): New function based 
+	on grub_fat_find_dir
+	(grub_fat_find_dir): use grub_fat_iterate_dir
+	(grub_fat_label): likewise
+
 2009-02-27  Robert Millan  <rmh@aybabtu.com>
 
 	Factorize elf32 / elf64 code in Multiboot loader.  This will

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-01 16:25 [PATCH] FAT, UFS and mtime phcoder
@ 2009-03-01 19:13 ` Bean
  2009-03-01 21:17   ` phcoder
  2009-03-11 21:32 ` phcoder
  2009-03-13 19:10 ` Robert Millan
  2 siblings, 1 reply; 12+ messages in thread
From: Bean @ 2009-03-01 19:13 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Mar 2, 2009 at 12:25 AM, phcoder <phcoder@gmail.com> wrote:
> Hello all. It seems that gcc has trouble with -m32 when structure is passed
> as argument. So I replaced that part by a pointer. Also I made some
> improvements to ufs code to support solaris branch of ufs. I tested it also
> with freebsd and netbsd's branch and it works fine on it too.
> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a patch
> with all 3 features. If it's really necessary I can split them but it
> requires a lot of unnecessary work

Hi,

Please don't merge patch, it makes it harder to track down bugs later.

Also, perhaps you should keep datetime.c as it is. I'm planning to
split the normal mode into separate components, it'd be nice if you
don't add files to the normal directory.

-- 
Bean



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-01 19:13 ` Bean
@ 2009-03-01 21:17   ` phcoder
  2009-03-02  3:58     ` Bean
  0 siblings, 1 reply; 12+ messages in thread
From: phcoder @ 2009-03-01 21:17 UTC (permalink / raw)
  To: The development of GRUB 2

Bean wrote:
> On Mon, Mar 2, 2009 at 12:25 AM, phcoder <phcoder@gmail.com> wrote:
>> Hello all. It seems that gcc has trouble with -m32 when structure is passed
>> as argument. So I replaced that part by a pointer. Also I made some
>> improvements to ufs code to support solaris branch of ufs. I tested it also
>> with freebsd and netbsd's branch and it works fine on it too.
>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a patch
>> with all 3 features. If it's really necessary I can split them but it
>> requires a lot of unnecessary work
> 
> Hi,
> 
> Please don't merge patch, it makes it harder to track down bugs later.
>
Actually these patches aren't merged. The problem is that my copyright 
assignment hasn't been signed by FSF yet so uncommited patches 
accumulate in my grub2 tree

 >
> Also, perhaps you should keep datetime.c as it is. I'm planning to
> split the normal mode into separate components, it'd be nice if you
> don't add files to the normal directory.
> 
Feel free to put datetime.c wherever you want

-- 

Regards
Vladimir 'phcoder' Serbinenko



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-01 21:17   ` phcoder
@ 2009-03-02  3:58     ` Bean
  2009-03-02  4:39       ` Pavel Roskin
  0 siblings, 1 reply; 12+ messages in thread
From: Bean @ 2009-03-02  3:58 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Mar 2, 2009 at 5:17 AM, phcoder <phcoder@gmail.com> wrote:
> Bean wrote:
>>
>> On Mon, Mar 2, 2009 at 12:25 AM, phcoder <phcoder@gmail.com> wrote:
>>>
>>> Hello all. It seems that gcc has trouble with -m32 when structure is
>>> passed
>>> as argument. So I replaced that part by a pointer. Also I made some
>>> improvements to ufs code to support solaris branch of ufs. I tested it
>>> also
>>> with freebsd and netbsd's branch and it works fine on it too.
>>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a
>>> patch
>>> with all 3 features. If it's really necessary I can split them but it
>>> requires a lot of unnecessary work
>>
>> Hi,
>>
>> Please don't merge patch, it makes it harder to track down bugs later.
>>
> Actually these patches aren't merged. The problem is that my copyright
> assignment hasn't been signed by FSF yet so uncommited patches accumulate in
> my grub2 tree

Hi,

I suggest that you try some VCS that supports local commits, such as
bzr or git. This make it easier to manage your patches before it's
committed to upstream.

-- 
Bean



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-02  3:58     ` Bean
@ 2009-03-02  4:39       ` Pavel Roskin
  0 siblings, 0 replies; 12+ messages in thread
From: Pavel Roskin @ 2009-03-02  4:39 UTC (permalink / raw)
  To: The development of GRUB 2

Quoting Bean <bean123ch@gmail.com>:

> I suggest that you try some VCS that supports local commits, such as
> bzr or git. This make it easier to manage your patches before it's
> committed to upstream.

I'm maintaining a git mirror.  The details are here:
http://repo.or.cz/w/grub2.git

The synchronization stopped a few days ago because an entry needed to  
be made for a new committer, but now the git mirror is up-to-date again.

I suggest using stgit with the repository.  It's a wrapper around git  
made specifically for working with patches.

-- 
Regards,
Pavel Roskin



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-01 16:25 [PATCH] FAT, UFS and mtime phcoder
  2009-03-01 19:13 ` Bean
@ 2009-03-11 21:32 ` phcoder
  2009-03-11 22:16   ` phcoder
  2009-03-13 19:10 ` Robert Millan
  2 siblings, 1 reply; 12+ messages in thread
From: phcoder @ 2009-03-11 21:32 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 659 bytes --]

Rediffed. Is the splitting in 3 patches actually necessary? If yes in 
which order do you want them to be applied?
phcoder wrote:
> Hello all. It seems that gcc has trouble with -m32 when structure is 
> passed as argument. So I replaced that part by a pointer. Also I made 
> some improvements to ufs code to support solaris branch of ufs. I tested 
> it also with freebsd and netbsd's branch and it works fine on it too.
> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a 
> patch with all 3 features. If it's really necessary I can split them but 
> it requires a lot of unnecessary work
> 


-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: fs.diff --]
[-- Type: text/x-patch, Size: 61555 bytes --]

Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revision 2026)
+++ conf/i386-pc.rmk	(working copy)
@@ -128,7 +128,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/color.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/color.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -209,7 +210,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c  normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -351,7 +352,7 @@ pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-efi.rmk
===================================================================
--- conf/i386-efi.rmk	(revision 2026)
+++ conf/i386-efi.rmk	(working copy)
@@ -52,7 +52,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c 		\
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -119,7 +120,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -177,7 +178,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/x86_64-efi.rmk
===================================================================
--- conf/x86_64-efi.rmk	(revision 2026)
+++ conf/x86_64-efi.rmk	(working copy)
@@ -54,7 +54,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c \
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -121,7 +122,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -179,7 +180,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-coreboot.rmk
===================================================================
--- conf/i386-coreboot.rmk	(revision 2026)
+++ conf/i386-coreboot.rmk	(working copy)
@@ -75,6 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/completion.c normal/main.c normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
@@ -121,7 +123,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/powerpc-ieee1275.rmk
===================================================================
--- conf/powerpc-ieee1275.rmk	(revision 2026)
+++ conf/powerpc-ieee1275.rmk	(working copy)
@@ -56,7 +56,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/misc.c kern/parser.c kern/partition.c kern/rescue.c	\
 	kern/term.c kern/list.c kern/handler.c fs/fshelp.c		\
 	normal/arg.c normal/cmdline.c normal/command.c			\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c 	\
 	normal/menu_text.c						\
 	normal/menu_entry.c normal/menu_viewer.c normal/misc.c 		\
@@ -133,7 +133,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/sparc64-ieee1275.rmk
===================================================================
--- conf/sparc64-ieee1275.rmk	(revision 2026)
+++ conf/sparc64-ieee1275.rmk	(working copy)
@@ -57,7 +57,8 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-
 #	kern/parser.c kern/partition.c kern/rescue.c kern/term.c	\
 #	kern/list.c kern/handler.c					\
 #	normal/arg.c normal/cmdline.c normal/command.c			\
-#	normal/completion.c normal/context.c normal/execute.c		\
+#	normal/completion.c normal/datetime.c normal/context.c		\
+#	normal/execute.c		\
 #	normal/function.c normal/lexer.c				\
 #	normal/main.c normal/menu.c normal/menu_entry.c			\
 #	normal/menu_text.c						\
@@ -166,7 +167,7 @@ sfs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/i386-ieee1275.rmk
===================================================================
--- conf/i386-ieee1275.rmk	(revision 2026)
+++ conf/i386-ieee1275.rmk	(working copy)
@@ -75,7 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/menu_text.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
@@ -112,7 +113,7 @@ pkglib_MODULES = normal.mod halt.mod reboot.mod su
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -192,7 +193,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: kern/fs.c
===================================================================
--- kern/fs.c	(revision 2026)
+++ kern/fs.c	(working copy)
@@ -65,10 +65,11 @@ grub_fs_t
 grub_fs_probe (grub_device_t device)
 {
   grub_fs_t p;
-  auto int dummy_func (const char *filename, int dir);
+  auto int dummy_func (const char *filename, 
+		       const struct grub_dirhook_info *info);
 
   int dummy_func (const char *filename __attribute__ ((unused)),
-		  int dir __attribute__ ((unused)))
+		  const struct grub_dirhook_info *info  __attribute__ ((unused)))
     {
       return 1;
     }
Index: kern/rescue.c
===================================================================
--- kern/rescue.c	(revision 2026)
+++ kern/rescue.c	(working copy)
@@ -176,9 +176,10 @@ grub_rescue_print_devices (const char *name)
 }
 
 static int
-grub_rescue_print_files (const char *filename, int dir)
+grub_rescue_print_files (const char *filename, 
+			  const struct grub_dirhook_info *info)
 {
-  grub_printf ("%s%s ", filename, dir ? "/" : "");
+  grub_printf ("%s%s ", filename, info->dir ? "/" : "");
   
   return 0;
 }
Index: hook/datehook.c
===================================================================
--- hook/datehook.c	(revision 2026)
+++ hook/datehook.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/env.h>
 #include <grub/misc.h>
 #include <grub/normal.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 static char *grub_datetime_names[] =
 {
Index: lib/efi/datetime.c
===================================================================
--- lib/efi/datetime.c	(revision 2026)
+++ lib/efi/datetime.c	(working copy)
@@ -21,7 +21,7 @@
 #include <grub/symbol.h>
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 grub_err_t
 grub_get_datetime (struct grub_datetime *datetime)
Index: lib/datetime.c
===================================================================
--- lib/datetime.c	(revision 2026)
+++ lib/datetime.c	(working copy)
@@ -1,49 +0,0 @@
-/* datetime.c - Module for common datetime function.  */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/lib/datetime.h>
-
-static char *grub_weekday_names[] =
-{
-  "Sunday",
-  "Monday",
-  "Tuesday",
-  "Wednesday",
-  "Thursday",
-  "Friday",
-  "Saturday",
-};
-
-int
-grub_get_weekday (struct grub_datetime *datetime)
-{
-  int a, y, m;
-
-  a = (14 - datetime->month) / 12;
-  y = datetime->year - a;
-  m = datetime->month + 12 * a - 2;
-
-  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
-}
-
-char *
-grub_get_weekday_name (struct grub_datetime *datetime)
-{
-  return grub_weekday_names[grub_get_weekday (datetime)];
-}
Index: fs/xfs.c
===================================================================
--- fs/xfs.c	(revision 2026)
+++ fs/xfs.c	(working copy)
@@ -620,7 +620,8 @@ grub_xfs_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_xfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_xfs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -633,14 +634,11 @@ grub_xfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/afs.c
===================================================================
--- fs/afs.c	(revision 2026)
+++ fs/afs.c	(working copy)
@@ -562,7 +562,8 @@ grub_afs_close (grub_file_t file)
 
 static grub_err_t
 grub_afs_dir (grub_device_t device, const char *path,
-              int (*hook) (const char *filename, int dir))
+              int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_afs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -575,14 +576,11 @@ grub_afs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ntfs.c
===================================================================
--- fs/ntfs.c	(revision 2026)
+++ fs/ntfs.c	(working copy)
@@ -864,7 +864,8 @@ fail:
 
 static grub_err_t
 grub_ntfs_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ntfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -877,14 +878,11 @@ grub_ntfs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/fat.c
===================================================================
--- fs/fat.c	(revision 2026)
+++ fs/fat.c	(working copy)
@@ -45,7 +45,8 @@
 				 | GRUB_FAT_ATTR_HIDDEN \
 				 | GRUB_FAT_ATTR_SYSTEM \
 				 | GRUB_FAT_ATTR_DIRECTORY \
-				 | GRUB_FAT_ATTR_ARCHIVE)
+				 | GRUB_FAT_ATTR_ARCHIVE \
+				 | GRUB_FAT_ATTR_VOLUME_ID)
 
 struct grub_fat_bpb
 {
@@ -467,51 +468,21 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
   return ret;
 }
 
-/* Find the underlying directory or file in PATH and return the
-   next path. If there is no next path or an error occurs, return NULL.
-   If HOOK is specified, call it with each file name.  */
-static char *
-grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
-		   const char *path,
-		   int (*hook) (const char *filename, int dir))
+static grub_err_t
+grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
+		      int (*hook) (const char *filename, 
+				   struct grub_fat_dir_entry *dir))
 {
   struct grub_fat_dir_entry dir;
-  char *dirname, *dirp;
   char *filename, *filep = 0;
   grub_uint16_t *unibuf;
   int slot = -1, slots = -1;
   int checksum = -1;
   grub_ssize_t offset = -sizeof(dir);
-  int call_hook;
   
   if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
-    {
-      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
-      return 0;
-    }
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
   
-  /* Extract a directory name.  */
-  while (*path == '/')
-    path++;
-
-  dirp = grub_strchr (path, '/');
-  if (dirp)
-    {
-      unsigned len = dirp - path;
-      
-      dirname = grub_malloc (len + 1);
-      if (! dirname)
-	return 0;
-
-      grub_memcpy (dirname, path, len);
-      dirname[len] = '\0';
-    }
-  else
-    /* This is actually a file.  */
-    dirname = grub_strdup (path);
-
-  call_hook = (! dirp && hook);
-  
   /* Allocate space enough to hold a long name.  */
   filename = grub_malloc (0x40 * 13 * 4 + 1);
   unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
@@ -519,7 +490,6 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
     {
       grub_free (filename);
       grub_free (unibuf);
-      grub_free (dirname);
       return 0;
     }
       
@@ -533,15 +503,8 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
       /* Read a directory entry.  */
       if ((grub_fat_read_data (disk, data, 0,
 			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno == GRUB_ERR_NONE && ! call_hook)
-	    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
-
-	  break;
-	}
-
+	   != sizeof (dir) || dir.name[0] == 0))
+	break;
       /* Handle long name entries.  */
       if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
 	{
@@ -594,22 +557,11 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 	      *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
 				   slots * 13) = '\0';
 	      
-	      if (*dirname == '\0' && call_hook)
-		{
-		  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-		    break;
-		  
-		  checksum = -1;
-		  continue;
-		}
-
-	      if (grub_strcmp (dirname, filename) == 0)
-		{
-		  if (call_hook)
-		    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
-		  
-		  break;
-		}
+	      if (hook (filename, &dir))
+		break;
+	      
+	      checksum = -1;
+	      continue;
 	    }
 
 	  checksum = -1;
@@ -617,49 +569,122 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 
       /* Convert the 8.3 file name.  */
       filep = filename;
-      
-      for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*filep++ = grub_tolower (dir.name[i]);
-      
-      *filep = '.';
-      
-      for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*++filep = grub_tolower (dir.name[i]);
-
-      if (*filep != '.')
-	filep++;
-      
-      *filep = '\0';
-
-      if (*dirname == '\0' && call_hook)
+      if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
 	{
-	  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-	    break;
+	  for (i = 0; i < sizeof (dir.name) && dir.name[i] 
+		 && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = dir.name[i];
 	}
-      else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
+      else
 	{
-	  if (call_hook)
-	    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
+	  for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = grub_tolower (dir.name[i]);
+      
+	  *filep = '.';
+	  
+	  for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *++filep = grub_tolower (dir.name[i]);
 
-	  break;
+	  if (*filep != '.')
+	    filep++;
 	}
+      *filep = '\0';
+
+      if (hook (filename, &dir))
+	break;
     }
 
   grub_free (filename);
+
+  return grub_errno;
+}
+
+
+/* Find the underlying directory or file in PATH and return the
+   next path. If there is no next path or an error occurs, return NULL.
+   If HOOK is specified, call it with each file name.  */
+static char *
+grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
+		   const char *path,
+		   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
+{
+  char *dirname, *dirp;
+  int call_hook;
+  int found = 0;
+
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    struct grub_dirhook_info info;
+    grub_memset (&info, 0, sizeof (info));
+
+    info.dir = !!(dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+    info.case_insensitive = 1;
+
+    if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
+      return 0;
+    if (*dirname == '\0' && call_hook)
+      return hook (filename, &info);
+
+    if (grub_strcasecmp (dirname, filename) == 0)
+      {
+	found = 1;
+	data->attr = dir->attr;
+	data->file_size = grub_le_to_cpu32 (dir->file_size);
+	data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
+			      | grub_le_to_cpu16 (dir->first_cluster_low));
+	data->cur_cluster_num = ~0U;
+
+	if (call_hook)
+	  hook (filename, &info);
+	    
+	return 1;
+      }
+    return 0;
+  }
+  
+  if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
+      return 0;
+    }
+  
+  /* Extract a directory name.  */
+  while (*path == '/')
+    path++;
+
+  dirp = grub_strchr (path, '/');
+  if (dirp)
+    {
+      unsigned len = dirp - path;
+      
+      dirname = grub_malloc (len + 1);
+      if (! dirname)
+	return 0;
+
+      grub_memcpy (dirname, path, len);
+      dirname[len] = '\0';
+    }
+  else
+    /* This is actually a file.  */
+    dirname = grub_strdup (path);
+
+  call_hook = (! dirp && hook);
+  
+  grub_fat_iterate_dir (disk, data, iter_hook);
+  if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
+    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
   grub_free (dirname);
 
-  data->attr = dir.attr;
-  data->file_size = grub_le_to_cpu32 (dir.file_size);
-  data->file_cluster = ((grub_le_to_cpu16 (dir.first_cluster_high) << 16)
-			| grub_le_to_cpu16 (dir.first_cluster_low));
-  data->cur_cluster_num = ~0U;
-  
-  return dirp;
+  return found ? dirp : 0;
 }
 
 static grub_err_t
 grub_fat_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_fat_data *data = 0;
   grub_disk_t disk = device->disk;
@@ -773,8 +798,17 @@ grub_fat_label (grub_device_t device, char **label
 {
   struct grub_fat_data *data;
   grub_disk_t disk = device->disk;
-  grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
 
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
+      {
+	*label = grub_strdup (filename);
+	return 1;
+      }
+    return 0;
+  }
 
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
@@ -790,37 +824,10 @@ grub_fat_label (grub_device_t device, char **label
       return 0;
     }
 
-  while (1)
-    {
-      struct grub_fat_dir_entry dir;
-
-      /* Adjust the offset.  */
-      offset += sizeof (dir);
-      
-      /* Read a directory entry.  */
-      if ((grub_fat_read_data (disk, data, 0,
-			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno != GRUB_ERR_NONE)
-	    goto fail;
-	  else
-	    {
-	      *label = 0;
-	      return GRUB_ERR_NONE;
-	    }
-	}
-
-      if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
-	{
-	  *label = grub_strndup ((char *) dir.name, 11);
-	  return GRUB_ERR_NONE;
-	}
-    }
-
   *label = 0;
   
+  grub_fat_iterate_dir (disk, data, iter_hook);
+
  fail:
 
 #ifndef GRUB_UTIL
Index: fs/udf.c
===================================================================
--- fs/udf.c	(revision 2026)
+++ fs/udf.c	(working copy)
@@ -768,7 +768,8 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
 
 static grub_err_t
 grub_udf_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_udf_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -782,14 +783,11 @@ grub_udf_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/iso9660.c
===================================================================
--- fs/iso9660.c	(revision 2026)
+++ fs/iso9660.c	(working copy)
@@ -666,7 +666,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
 \f
 static grub_err_t
 grub_iso9660_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_iso9660_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -680,14 +681,11 @@ grub_iso9660_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/affs.c
===================================================================
--- fs/affs.c	(revision 2026)
+++ fs/affs.c	(working copy)
@@ -456,7 +456,8 @@ grub_affs_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_affs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_affs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -469,14 +470,11 @@ grub_affs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/hfs.c
===================================================================
--- fs/hfs.c	(revision 2026)
+++ fs/hfs.c	(working copy)
@@ -721,7 +721,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, con
 \f
 static grub_err_t
 grub_hfs_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename,
+			       const struct grub_dirhook_info *info))
 {
   int inode;
 
@@ -732,13 +733,17 @@ grub_hfs_dir (grub_device_t device, const char *pa
       char fname[32] = { 0 };
       char *filetype = rec->data;
       struct grub_hfs_catalog_key *ckey = rec->key;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       grub_strncpy (fname, (char *) (ckey->str), ckey->strlen);
       
-      if (*filetype == GRUB_HFS_FILETYPE_DIR)
-	return hook (fname, 1);
-      else if (*filetype == GRUB_HFS_FILETYPE_FILE)
-	return hook (fname, 0);
+      if (*filetype == GRUB_HFS_FILETYPE_DIR 
+	  || *filetype == GRUB_HFS_FILETYPE_FILE)
+	{
+	  info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR);
+	  return hook (fname, &info);
+	}
       return 0;
     }
   
Index: fs/reiserfs.c
===================================================================
--- fs/reiserfs.c	(revision 2026)
+++ fs/reiserfs.c	(working copy)
@@ -1266,7 +1266,8 @@ grub_reiserfs_close (grub_file_t file)
 /* Call HOOK with each file under DIR.  */
 static grub_err_t
 grub_reiserfs_dir (grub_device_t device, const char *path,
-                   int (*hook) (const char *filename, int dir))
+                   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
 {
   struct grub_reiserfs_data *data = 0;
   struct grub_fshelp_node root, *found;
@@ -1280,12 +1281,11 @@ grub_reiserfs_dir (grub_device_t device, const cha
                                 enum grub_fshelp_filetype filetype,
                                 grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-        return hook (filename, 1);
-      else
-        return hook (filename, 0);
+      return hook (filename, &info);
     }
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
Index: fs/jfs.c
===================================================================
--- fs/jfs.c	(revision 2026)
+++ fs/jfs.c	(working copy)
@@ -728,7 +728,8 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *dat
 
 static grub_err_t
 grub_jfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_jfs_data *data = 0;
   struct grub_jfs_diropen *diro = 0;
@@ -752,14 +753,15 @@ grub_jfs_dir (grub_device_t device, const char *pa
   while (grub_jfs_getent (diro) != GRUB_ERR_OUT_OF_RANGE)
     {
       struct grub_jfs_inode inode;
-      int isdir;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       if (grub_jfs_read_inode (data, diro->ino, &inode))
 	goto fail;
       
-      isdir = (grub_le_to_cpu32 (inode.mode)
-	       & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
-      if (hook (diro->name, isdir))
+      info.dir = (grub_le_to_cpu32 (inode.mode)
+		  & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
+      if (hook (diro->name, &info))
 	goto fail;
     }
   
Index: fs/ext2.c
===================================================================
--- fs/ext2.c	(revision 2026)
+++ fs/ext2.c	(working copy)
@@ -788,7 +788,8 @@ grub_ext2_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_ext2_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ext2_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -801,14 +802,24 @@ grub_ext2_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      if (! node->inode_read)
+	{
+	  grub_ext2_read_inode (data, node->ino, &node->inode);
+	  if (!grub_errno)
+	    node->inode_read = 1;
+	  grub_errno = GRUB_ERR_NONE;
+	}
+      if (node->inode_read)
+	{
+	  info.mtimeset = 1;
+	  info.mtime = grub_le_to_cpu32 (node->inode.mtime);
+	}
+
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -895,6 +906,34 @@ grub_ext2_uuid (grub_device_t device, char **uuid)
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ext2_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ext2_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_le_to_cpu32 (data->sblock.utime);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_ext2_fs =
   {
@@ -905,6 +944,7 @@ static struct grub_fs grub_ext2_fs =
     .close = grub_ext2_close,
     .label = grub_ext2_label,
     .uuid = grub_ext2_uuid,
+    .mtime = grub_ext2_mtime,
     .next = 0
   };
 
Index: fs/minix.c
===================================================================
--- fs/minix.c	(revision 2026)
+++ fs/minix.c	(working copy)
@@ -461,7 +461,8 @@ grub_minix_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_minix_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_minix_data *data = 0;
   struct grub_minix_sblock *sblock;
@@ -492,6 +493,9 @@ grub_minix_dir (grub_device_t device, const char *
       grub_uint16_t ino;
       char filename[data->filename_size + 1];
       int dirino = data->ino;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+
       
       if (grub_minix_read_file (data, 0, pos, sizeof (ino),
 				(char *) &ino) < 0)
@@ -506,8 +510,9 @@ grub_minix_dir (grub_device_t device, const char *
       /* The filetype is not stored in the dirent.  Read the inode to
 	 find out the filetype.  This *REALLY* sucks.  */
       grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
-      if (hook (filename, ((GRUB_MINIX_INODE_MODE (data) 
-			    & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR)) ? 1 : 0)
+      info.dir = ((GRUB_MINIX_INODE_MODE (data) 
+		   & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
+      if (hook (filename, &info) ? 1 : 0)
 	break;
       
       /* Load the old inode back in.  */
Index: fs/hfsplus.c
===================================================================
--- fs/hfsplus.c	(revision 2026)
+++ fs/hfsplus.c	(working copy)
@@ -57,9 +57,11 @@ struct grub_hfsplus_volheader
   grub_uint16_t magic;
   grub_uint16_t version;
   grub_uint32_t attributes;
-  grub_uint8_t unused[32];
+  grub_uint8_t unused1[12];
+  grub_uint32_t utime;
+  grub_uint8_t unused2[16];
   grub_uint32_t blksize;
-  grub_uint8_t unused2[68];
+  grub_uint8_t unused3[68];
   struct grub_hfsplus_forkdata allocations_file;
   struct grub_hfsplus_forkdata extents_file;
   struct grub_hfsplus_forkdata catalog_file;
@@ -133,9 +135,11 @@ struct grub_hfsplus_catfile
   grub_uint16_t flags;
   grub_uint32_t reserved;
   grub_uint32_t fileid;
-  grub_uint8_t unused1[30];
+  grub_uint8_t unused1[4];
+  grub_uint32_t mtime;
+  grub_uint8_t unused2[22];
   grub_uint16_t mode;
-  grub_uint8_t unused2[44];
+  grub_uint8_t unused3[44];
   struct grub_hfsplus_forkdata data;
   struct grub_hfsplus_forkdata resource;
 } __attribute__ ((packed));
@@ -190,6 +194,7 @@ struct grub_fshelp_node
   struct grub_hfsplus_extent extents[8];
   grub_uint64_t size;
   grub_uint32_t fileid;
+  grub_int32_t mtime;
 };
 
 struct grub_hfsplus_btree
@@ -780,6 +785,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
 	  
 	  grub_memcpy (node->extents, fileinfo->data.extents,
 		       sizeof (node->extents));
+	  node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
 	  node->size = grub_be_to_cpu64 (fileinfo->data.size);
 	  node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
 
@@ -885,7 +891,8 @@ grub_hfsplus_read (grub_file_t file, char *buf, gr
 
 static grub_err_t
 grub_hfsplus_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_hfsplus_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -898,14 +905,14 @@ grub_hfsplus_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      info.mtimeset = 1;
+      info.mtime = node->mtime;
+      info.case_insensitive = !!(filetype & GRUB_FSHELP_CASE_INSENSITIVE);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -949,6 +956,34 @@ grub_hfsplus_label (grub_device_t device __attribu
 		     "partition is not implemented");
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_hfsplus_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_hfsplus_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_hfsplus_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_be_to_cpu32 (data->volheader.utime) - 2082844800;
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_hfsplus_fs =
   {
@@ -958,6 +993,7 @@ static struct grub_fs grub_hfsplus_fs =
     .read = grub_hfsplus_read,
     .close = grub_hfsplus_close,
     .label = grub_hfsplus_label,
+    .mtime = grub_hfsplus_mtime,
     .next = 0
   };
 
Index: fs/cpio.c
===================================================================
--- fs/cpio.c	(revision 2026)
+++ fs/cpio.c	(working copy)
@@ -183,7 +183,8 @@ fail:
 
 static grub_err_t
 grub_cpio_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_cpio_data *data;
   grub_uint32_t ofs;
@@ -227,7 +228,11 @@ grub_cpio_dir (grub_device_t device, const char *p
 
 	  if ((!prev) || (grub_strcmp (prev, name) != 0))
 	    {
-	      hook (name + len, p != NULL);
+	      struct grub_dirhook_info info;
+	      grub_memset (&info, 0, sizeof (info));
+	      info.dir = (p != NULL);
+
+	      hook (name + len, &info);
 	      if (prev)
 		grub_free (prev);
 	      prev = name;
Index: fs/sfs.c
===================================================================
--- fs/sfs.c	(revision 2026)
+++ fs/sfs.c	(working copy)
@@ -519,7 +519,8 @@ grub_sfs_read (grub_file_t file, char *buf, grub_s
 
 static grub_err_t
 grub_sfs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_sfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -532,14 +533,11 @@ grub_sfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ufs.c
===================================================================
--- fs/ufs.c	(revision 2026)
+++ fs/ufs.c	(working copy)
@@ -36,7 +36,10 @@
 #define GRUB_UFS_DIRBLKS	12
 #define GRUB_UFS_INDIRBLKS	3
 
-#define GRUB_UFS_ATTR_DIR	040000
+#define GRUB_UFS_ATTR_TYPE      0160000
+#define GRUB_UFS_ATTR_FILE	0100000
+#define GRUB_UFS_ATTR_DIR	0040000
+#define GRUB_UFS_ATTR_LNK       0120000
 
 #define GRUB_UFS_VOLNAME_LEN	32
 
@@ -51,6 +54,8 @@
                            grub_le_to_cpu##bits1 (data->inode.field) : \
                            grub_le_to_cpu##bits2 (data->inode2.field))
 #define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
+#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
+
 #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
 #define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
@@ -71,29 +76,35 @@ struct grub_ufs_sblock
   
   /* The start of the cylinder group.  */
   grub_uint32_t cylg_offset;
+  grub_uint8_t unused3[4];
+
+  grub_uint32_t mtime;
+  grub_uint8_t unused4[12];
   
-  grub_uint8_t unused3[20];
-  
   /* The size of a block in bytes.  */
   grub_int32_t bsize;
-  grub_uint8_t unused4[48];
+  grub_uint8_t unused5[48];
   
   /* The size of filesystem blocks to disk blocks.  */
   grub_uint32_t log2_blksz;
-  grub_uint8_t unused5[80];
+  grub_uint8_t unused6[80];
   
   /* Inodes stored per cylinder group.  */
   grub_uint32_t ino_per_group;
   
   /* The frags per cylinder group.  */
   grub_uint32_t frags_per_group;
+  grub_uint8_t unused7[19];
+  grub_uint8_t flags;
   
-  grub_uint8_t unused7[488];
+  grub_uint8_t unused8[468];
 
   /* Volume name for UFS2.  */
   grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
+  grub_uint8_t unused9[232];
 
-  grub_uint8_t unused8[660];
+  grub_uint64_t mtime2;
+  grub_uint8_t unused10[420];
   
   /* Magic value to check if this is really a UFS filesystem.  */
   grub_uint32_t magic;
@@ -124,7 +135,7 @@ struct grub_ufs_inode
   grub_uint32_t gen;
   grub_uint32_t unused;
   grub_uint8_t pad[12];
-};
+} __attribute__ ((packed));
 
 /* UFS inode.  */
 struct grub_ufs2_inode
@@ -160,16 +171,23 @@ struct grub_ufs2_inode
   };
 
   grub_uint8_t unused[24];
-};
+} __attribute__ ((packed));
 
 /* Directory entry.  */
 struct grub_ufs_dirent
 {
   grub_uint32_t ino;
   grub_uint16_t direntlen;
-  grub_uint8_t filetype;
-  grub_uint8_t namelen;
-};
+  union
+  {
+    grub_uint16_t namelen;
+    struct
+    {
+      grub_uint8_t filetype_bsd;
+      grub_uint8_t namelen_bsd;      
+    };
+  };
+} __attribute__ ((packed));
 
 /* Information about a "mounted" ufs filesystem.  */
 struct grub_ufs_data
@@ -225,24 +243,24 @@ grub_ufs_get_file_block (struct grub_ufs_data *dat
       return (data->ufs_type == UFS1) ? indir[blk] : indir[blk << 1];
     }
   blk -= indirsz;
-  
+
   /* Double indirect block.  */
-  if (blk < UFS_BLKSZ (sblock) / indirsz)
+  if (blk < indirsz * indirsz)
     {
       grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
       
       grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       grub_disk_read (data->disk,
-      		      (data->ufs_type == UFS1) ?
-		      indir[blk / indirsz] : indir [(blk / indirsz) << 1],
+      		      ((data->ufs_type == UFS1) ?
+		      indir[blk / indirsz] : indir [(blk / indirsz) << 1]) 
+		      << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       
       return (data->ufs_type == UFS1) ?
 	     indir[blk % indirsz] : indir[(blk % indirsz) << 1];
     }
 
-
   grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 	      "ufs does not support triple indirect blocks");
   return 0;
@@ -320,7 +338,7 @@ grub_ufs_read_file (struct grub_ufs_data *data,
 /* Read inode INO from the mounted filesystem described by DATA.  This
    inode is used by default now.  */
 static grub_err_t
-grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
+grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
 {
   struct grub_ufs_sblock *sblock = &data->sblock;
   
@@ -335,8 +353,12 @@ static grub_err_t
   
   if (data->ufs_type == UFS1)
     {
-      struct grub_ufs_inode *inode = &data->inode;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -347,8 +369,12 @@ static grub_err_t
     }
   else
     {
-      struct grub_ufs2_inode *inode = &data->inode2;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode2;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -358,7 +384,6 @@ static grub_err_t
 		      (char *) inode);
     }
   
-  data->ino = ino;
   return grub_errno;
 }
 
@@ -372,9 +397,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
   
   if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
     return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
-  
-  if (INODE_SIZE (data) < (GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS
-			  * INODE_BLKSZ (data)))
+
+  if (INODE_NBLOCKS (data) == 0)
     grub_strcpy (symlink, (char *) INODE (data, symlink));
   else
     {
@@ -390,7 +414,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
     ino = GRUB_UFS_INODE;
   
   /* Now load in the old inode.  */
-  if (grub_ufs_read_inode (data, ino))
+  if (grub_ufs_read_inode (data, ino, 0))
     return grub_errno;
   
   grub_ufs_find_file (data, symlink);
@@ -433,29 +457,34 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
   do
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_strlen (name) == 0)
 	return GRUB_ERR_NONE;
       
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	return grub_errno;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
 
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  return grub_errno;
 	
-	filename[dirent.namelen] = '\0';
+	filename[namelen] = '\0';
 	
 	if (!grub_strcmp (name, filename))
 	  {
 	    dirino = data->ino;
-	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino));
-	    
-	    if (dirent.filetype == GRUB_UFS_FILETYPE_LNK)
+	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino), 0);
+
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
+		== GRUB_UFS_ATTR_LNK)
 	      {
 		grub_ufs_lookup_symlink (data, dirino);
 		if (grub_errno)
@@ -475,7 +504,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
 		next++;
 	      }
 	    
-	    if (!(dirent.filetype & GRUB_UFS_FILETYPE_DIR))
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 	      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 	    
 	    continue;
@@ -544,7 +573,8 @@ grub_ufs_mount (grub_disk_t disk)
 
 static grub_err_t
 grub_ufs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ufs_data *data;
   struct grub_ufs_sblock *sblock;
@@ -554,7 +584,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, GRUB_UFS_INODE);
+  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
   if (grub_errno)
     return grub_errno;
   
@@ -570,7 +600,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (grub_errno)
     goto fail;  
   
-  if (!(INODE_MODE (data) & GRUB_UFS_ATTR_DIR))
+  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
     {
       grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
       goto fail;
@@ -579,20 +609,45 @@ grub_ufs_dir (grub_device_t device, const char *pa
   while (pos < INODE_SIZE (data))
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	break;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
+	struct grub_dirhook_info info;
+	grub_memset (&info, 0, sizeof (info));
 	
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  break;
 	
-	filename[dirent.namelen] = '\0';
-	if (hook (filename, dirent.filetype == GRUB_UFS_FILETYPE_DIR))
+	filename[namelen] = '\0';
+	if (data->ufs_type == UFS1)
+	  {
+	    struct grub_ufs_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+	else
+	  {
+	    struct grub_ufs2_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+
+	if (hook (filename, &info))
 	  break;
       }
       
@@ -615,7 +670,7 @@ grub_ufs_open (struct grub_file *file, const char
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, 2);
+  grub_ufs_read_inode (data, 2, 0);
   if (grub_errno)
     {
       grub_free (data);
@@ -688,6 +743,34 @@ grub_ufs_label (grub_device_t device, char **label
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ufs_data *data = 0;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ufs_mount (device->disk);
+  if (!data)
+    *tm = 0;
+  else if (data->ufs_type == UFS1)
+    *tm = grub_le_to_cpu32 (data->sblock.mtime);
+  else
+    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+}
+
+
 \f
 static struct grub_fs grub_ufs_fs =
   {
@@ -697,6 +780,7 @@ static struct grub_fs grub_ufs_fs =
     .read = grub_ufs_read,
     .close = grub_ufs_close,
     .label = grub_ufs_label,
+    .mtime = grub_ufs_mtime,
     .next = 0
   };
 
Index: include/grub/fs.h
===================================================================
--- include/grub/fs.h	(revision 2026)
+++ include/grub/fs.h	(working copy)
@@ -27,6 +27,14 @@
 /* Forward declaration is required, because of mutual reference.  */
 struct grub_file;
 
+struct grub_dirhook_info
+{
+  int dir:1;
+  int mtimeset:1;
+  int case_insensitive:1;
+  grub_int32_t mtime;
+};
+
 /* Filesystem descriptor.  */
 struct grub_fs
 {
@@ -35,7 +43,8 @@ struct grub_fs
 
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
-		     int (*hook) (const char *filename, int dir));
+		     int (*hook) (const char *filename, 
+				  const struct grub_dirhook_info *info));
   
   /* Open a file named NAME and initialize FILE.  */
   grub_err_t (*open) (struct grub_file *file, const char *name);
@@ -56,6 +65,9 @@ struct grub_fs
      caller.  */
   grub_err_t (*uuid) (grub_device_t device, char **uuid);
 
+  /* Get writing time of filesystem. */
+  grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf);
+
   /* The next filesystem.  */
   struct grub_fs *next;
 };
Index: include/grub/fshelp.h
===================================================================
--- include/grub/fshelp.h	(revision 2026)
+++ include/grub/fshelp.h	(working copy)
@@ -27,6 +27,8 @@
 typedef struct grub_fshelp_node *grub_fshelp_node_t;
 
 #define GRUB_FSHELP_CASE_INSENSITIVE	0x100
+#define GRUB_FSHELP_TYPE_MASK	0xff
+#define GRUB_FSHELP_FLAGS_MASK	0x100
 
 enum grub_fshelp_filetype
   {
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2026)
+++ ChangeLog	(working copy)
@@ -1,3 +1,77 @@
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	UFS improvements
+
+	* fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
+	(GRUB_UFS_ATTR_FILE): likewise
+	(GRUB_UFS_ATTR_LNK): likewise
+	(GRUB_UFS_BSD_DIRENT): likewise
+	(struct grub_ufs_sblock): new fields mtime and flags
+	(struct grub_ufs_dirent): added fields for non-BSD dirents
+	(grub_ufs_get_file_block): fixed double indirect handling
+	(grub_ufs_read_inode): new parameter to read inode to a separate buffer
+	all users updated
+	(grub_ufs_find_file): support for non-BSD dirents
+	(grub_ufs_dir): likewise and mtime support
+	(grub_ufs_mtime): new function
+
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Support for mtime and further expandability of dir command
+
+	* include/grub/lib/datetime.h: moved to ...
+	* include/grub/datetime.h: ... moved here and added 
+	declaration of grub_unixtime2datetime. All users updated
+	* include/grub/fs.h: new syntax for dir and mtime functionin 
+	struct grub_fs 
+	* include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
+	and GRUB_FSHELP_FLAGS_MASK
+	* commands/ls.c (grub_ls_list_files): Write mtime in long format
+	* fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
+	(grub_ext2_mtime): new function
+	* fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply mtime
+	(grub_hfsplus_mtime): new function
+	* fs/affs.c (grub_affs_dir): use new dir syntax
+	* fs/afs.c (grub_afs_dir): likewise
+	* fs/cpio.c (grub_cpio_dir): likewise
+	* fs/fat.c (grub_fat_find_dir): likewise
+	* fs/hfs.c (grub_hfs_dir): likewise
+	* fs/iso9660.c (grub_iso9660_dir): likewise
+	* fs/jfs.c (grub_jfs_dir): likewise
+	* fs/minix.c (grub_minix_dir): likewise
+	* fs/ntfs.c (grub_ntfs_dir): likewise
+	* fs/reiserfs.c (grub_reiserfs_dir): likewise
+	* fs/sfs.c (grub_sfs_dir): likewise
+	* fs/xfs.c (grub_xfs_dir): likewise
+	* fs/ufs.c (grub_ufs_dir): likewise
+	* util/hostfs.c (grub_hostfs_dir): likewise
+	* lib/datetime.c: moved to ...
+	* normal/datetime.c: ... moved here
+	(grub_unixtime2datetime): new function
+	* kern/rescue.c (grub_rescue_print_files): use new dir syntax
+	* normal/completition.c (iterate_dir): use new dir syntax
+	* normal/misc.c (grub_normal_print_device_info): tell the 
+	last modification time of a volume
+	* kern/fs.c (grub_fs_probe): updated dummy function to use new syntax 
+	* conf/common.rmk: added lib/datetime.c to ls.mod
+	* conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu 
+	and normal.mod. Removed lib/datetime.c from datetime.mod
+	* conf/i386-efi.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise	
+	* conf/i386-pc.rmk: likewise
+	* conf/powerpc-ieee1275.rmk: likewise
+	* conf/sparc64-ieee1275.rmk: likewise	
+	* conf/x86_64-efi.rmk: likewise	
+ 	
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Trim trailing spaces in FAT label and support mtools-like labels
+	
+	* fs/fat.c (grub_fat_iterate_dir): New function based 
+	on grub_fat_find_dir
+	(grub_fat_find_dir): use grub_fat_iterate_dir
+	(grub_fat_label): likewise 
+
 2009-03-11  Felix Zielcke  <fzielcke@z-51.de>
 
 	* conf/powerpc-ieee1275.rmk (kernel_elf_SOURCES): Add `kern/list.c' and
Index: normal/completion.c
===================================================================
--- normal/completion.c	(revision 2026)
+++ normal/completion.c	(working copy)
@@ -123,9 +123,9 @@ iterate_partition (grub_disk_t disk, const grub_pa
 }
 
 static int
-iterate_dir (const char *filename, int dir)
+iterate_dir (const char *filename, const struct grub_dirhook_info *info)
 {
-  if (! dir)
+  if (! info->dir)
     {
       const char *prefix;
       if (cmdline_state == GRUB_PARSER_STATE_DQUOTE)
Index: normal/misc.c
===================================================================
--- normal/misc.c	(revision 2026)
+++ normal/misc.c	(working copy)
@@ -23,6 +23,7 @@
 #include <grub/err.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/datetime.h>
 
 /* Print the information on the device NAME.  */
 grub_err_t
@@ -63,6 +64,23 @@ grub_normal_print_device_info (const char *name)
 		}
 	      grub_errno = GRUB_ERR_NONE;
 	    }
+	  if (fs->mtime)
+	    {
+	      grub_int32_t tm;
+	      struct grub_datetime datetime;
+	      (fs->mtime) (dev, &tm);
+	      if (grub_errno == GRUB_ERR_NONE)
+		{
+		  grub_unixtime2datetime (tm, &datetime);
+		  grub_printf (", Last modification time %d-%02d-%02d "
+			       "%02d:%02d:%02d %s",
+			       datetime.year, datetime.month, datetime.day,
+			       datetime.hour, datetime.minute, datetime.second,
+			       grub_get_weekday_name (&datetime));
+
+		}
+	      grub_errno = GRUB_ERR_NONE;
+	    }
 	  if (fs->uuid)
 	    {
 	      char *uuid;
Index: commands/date.c
===================================================================
--- commands/date.c	(revision 2026)
+++ commands/date.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/arg.h>
 #include <grub/err.h>
 #include <grub/misc.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 #define GRUB_DATETIME_SET_YEAR		1
 #define GRUB_DATETIME_SET_MONTH		2
Index: commands/ls.c
===================================================================
--- commands/ls.c	(revision 2026)
+++ commands/ls.c	(working copy)
@@ -29,6 +29,7 @@
 #include <grub/term.h>
 #include <grub/partition.h>
 #include <grub/file.h>
+#include <grub/datetime.h>
 
 static const struct grub_arg_option options[] =
   {
@@ -68,25 +69,29 @@ grub_ls_list_files (char *dirname, int longlist, i
   grub_fs_t fs;
   const char *path;
   grub_device_t dev;
-  auto int print_files (const char *filename, int dir);
-  auto int print_files_long (const char *filename, int dir);
+
+  auto int print_files (const char *filename, 
+			const struct grub_dirhook_info *info);
+  auto int print_files_long (const char *filename, 
+			     const struct grub_dirhook_info *info);
   
-  int print_files (const char *filename, int dir)
+  int print_files (const char *filename, const struct grub_dirhook_info *info)
     {
       if (all || filename[0] != '.')
-	grub_printf ("%s%s ", filename, dir ? "/" : "");
+	grub_printf ("%s%s ", filename, info->dir ? "/" : "");
       
       return 0;
     }
      
-  int print_files_long (const char *filename, int dir)
+  int print_files_long (const char *filename, 
+			const struct grub_dirhook_info *info)
     {
       char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1];
 
       if ((! all) && (filename[0] == '.'))
 	return 0;
 
-      if (! dir)
+      if (! info->dir)
 	{
 	  grub_file_t file;
 	  
@@ -138,7 +143,23 @@ grub_ls_list_files (char *dirname, int longlist, i
       else
 	grub_printf ("%-12s", "DIR");
 
-      grub_printf ("%s%s\n", filename, dir ? "/" : "");
+      if (info->mtimeset)
+	{
+	  struct grub_datetime datetime;
+	  grub_unixtime2datetime (info->mtime, &datetime);
+	  if (human)
+	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
+			 datetime.year, datetime.month, datetime.day,
+			 datetime.hour, datetime.minute, 
+			 datetime.second,
+			 grub_get_weekday_name (&datetime));
+	  else
+	    grub_printf (" %04d%02d%02d%02d%02d%02d ",
+			 datetime.year, datetime.month, 
+			 datetime.day, datetime.hour, 
+			 datetime.minute, datetime.second);
+	}
+      grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
 
       return 0;
     }
@@ -181,7 +202,7 @@ grub_ls_list_files (char *dirname, int longlist, i
 	  /* PATH might be a regular file.  */
 	  char *p;
 	  grub_file_t file;
-
+	  struct grub_dirhook_info info;
 	  grub_errno = 0;
 	  
 	  file = grub_file_open (dirname);
@@ -196,10 +217,11 @@ grub_ls_list_files (char *dirname, int longlist, i
 	    goto fail;
 
 	  all = 1;
+	  grub_memset (&info, 0, sizeof (info));
 	  if (longlist)
-	    print_files_long (p, 0);
+	    print_files_long (p, &info);
 	  else
-	    print_files (p, 0);
+	    print_files (p, &info);
 
 	  grub_free (dirname);
 	}
Index: util/hostfs.c
===================================================================
--- util/hostfs.c	(revision 2026)
+++ util/hostfs.c	(working copy)
@@ -16,7 +16,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
-
+#define _BSD_SOURCE
 #include <grub/fs.h>
 #include <grub/file.h>
 #include <grub/disk.h>
@@ -57,7 +57,8 @@ is_dir (const char *path, const char *name)
 
 static grub_err_t
 grub_hostfs_dir (grub_device_t device, const char *path, 
-		 int (*hook) (const char *filename, int dir))
+		 int (*hook) (const char *filename, 
+			      const struct grub_dirhook_info *info))
 {
   DIR *dir;
 
@@ -73,16 +74,20 @@ grub_hostfs_dir (grub_device_t device, const char
   while (1)
     {
       struct dirent *de;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
 
       de = readdir (dir);
       if (! de)
 	break;
 
 #ifdef DT_DIR
-      hook (de->d_name, de->d_type == DT_DIR);
+      info.dir = (de->d_type == DT_DIR);
 #else
-      hook (de->d_name, is_dir (path, de->d_name));
+      info.dir = !!is_dir (path, de->d_name);
 #endif
+      hook (de->d_name, &info);
+
     }
 
   closedir (dir);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-11 21:32 ` phcoder
@ 2009-03-11 22:16   ` phcoder
  0 siblings, 0 replies; 12+ messages in thread
From: phcoder @ 2009-03-11 22:16 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 727 bytes --]

normal/datetime.c was missing
phcoder wrote:
> Rediffed. Is the splitting in 3 patches actually necessary? If yes in 
> which order do you want them to be applied?
> phcoder wrote:
>> Hello all. It seems that gcc has trouble with -m32 when structure is 
>> passed as argument. So I replaced that part by a pointer. Also I made 
>> some improvements to ufs code to support solaris branch of ufs. I 
>> tested it also with freebsd and netbsd's branch and it works fine on 
>> it too.
>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a 
>> patch with all 3 features. If it's really necessary I can split them 
>> but it requires a lot of unnecessary work
>>
> 
> 


-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: fs.diff --]
[-- Type: text/x-patch, Size: 64700 bytes --]

Index: conf/i386-pc.rmk
===================================================================
--- conf/i386-pc.rmk	(revision 2028)
+++ conf/i386-pc.rmk	(working copy)
@@ -128,7 +128,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/color.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/color.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -209,7 +210,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c  normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -351,7 +352,7 @@ pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-efi.rmk
===================================================================
--- conf/i386-efi.rmk	(revision 2028)
+++ conf/i386-efi.rmk	(working copy)
@@ -52,7 +52,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c 		\
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -119,7 +120,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -177,7 +178,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/x86_64-efi.rmk
===================================================================
--- conf/x86_64-efi.rmk	(revision 2028)
+++ conf/x86_64-efi.rmk	(working copy)
@@ -54,7 +54,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c \
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -121,7 +122,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kerne
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -179,7 +180,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: conf/i386-coreboot.rmk
===================================================================
--- conf/i386-coreboot.rmk	(revision 2028)
+++ conf/i386-coreboot.rmk	(working copy)
@@ -75,6 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/completion.c normal/main.c normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
@@ -121,7 +123,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/powerpc-ieee1275.rmk
===================================================================
--- conf/powerpc-ieee1275.rmk	(revision 2028)
+++ conf/powerpc-ieee1275.rmk	(working copy)
@@ -56,7 +56,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/misc.c kern/parser.c kern/partition.c kern/rescue.c	\
 	kern/term.c kern/list.c kern/handler.c fs/fshelp.c		\
 	normal/arg.c normal/cmdline.c normal/command.c			\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c 	\
 	normal/menu_text.c						\
 	normal/menu_entry.c normal/menu_viewer.c normal/misc.c 		\
@@ -133,7 +133,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/sparc64-ieee1275.rmk
===================================================================
--- conf/sparc64-ieee1275.rmk	(revision 2028)
+++ conf/sparc64-ieee1275.rmk	(working copy)
@@ -57,7 +57,8 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-
 #	kern/parser.c kern/partition.c kern/rescue.c kern/term.c	\
 #	kern/list.c kern/handler.c					\
 #	normal/arg.c normal/cmdline.c normal/command.c			\
-#	normal/completion.c normal/context.c normal/execute.c		\
+#	normal/completion.c normal/datetime.c normal/context.c		\
+#	normal/execute.c		\
 #	normal/function.c normal/lexer.c				\
 #	normal/main.c normal/menu.c normal/menu_entry.c			\
 #	normal/menu_text.c						\
@@ -166,7 +167,7 @@ sfs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
Index: conf/i386-ieee1275.rmk
===================================================================
--- conf/i386-ieee1275.rmk	(revision 2028)
+++ conf/i386-ieee1275.rmk	(working copy)
@@ -75,7 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/menu_text.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
@@ -112,7 +113,7 @@ pkglib_MODULES = normal.mod halt.mod reboot.mod su
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -192,7 +193,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
Index: kern/fs.c
===================================================================
--- kern/fs.c	(revision 2028)
+++ kern/fs.c	(working copy)
@@ -65,10 +65,11 @@ grub_fs_t
 grub_fs_probe (grub_device_t device)
 {
   grub_fs_t p;
-  auto int dummy_func (const char *filename, int dir);
+  auto int dummy_func (const char *filename, 
+		       const struct grub_dirhook_info *info);
 
   int dummy_func (const char *filename __attribute__ ((unused)),
-		  int dir __attribute__ ((unused)))
+		  const struct grub_dirhook_info *info  __attribute__ ((unused)))
     {
       return 1;
     }
Index: kern/rescue.c
===================================================================
--- kern/rescue.c	(revision 2028)
+++ kern/rescue.c	(working copy)
@@ -176,9 +176,10 @@ grub_rescue_print_devices (const char *name)
 }
 
 static int
-grub_rescue_print_files (const char *filename, int dir)
+grub_rescue_print_files (const char *filename, 
+			  const struct grub_dirhook_info *info)
 {
-  grub_printf ("%s%s ", filename, dir ? "/" : "");
+  grub_printf ("%s%s ", filename, info->dir ? "/" : "");
   
   return 0;
 }
Index: hook/datehook.c
===================================================================
--- hook/datehook.c	(revision 2028)
+++ hook/datehook.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/env.h>
 #include <grub/misc.h>
 #include <grub/normal.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 static char *grub_datetime_names[] =
 {
Index: lib/efi/datetime.c
===================================================================
--- lib/efi/datetime.c	(revision 2028)
+++ lib/efi/datetime.c	(working copy)
@@ -21,7 +21,7 @@
 #include <grub/symbol.h>
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 grub_err_t
 grub_get_datetime (struct grub_datetime *datetime)
Index: lib/datetime.c
===================================================================
--- lib/datetime.c	(revision 2028)
+++ lib/datetime.c	(working copy)
@@ -1,49 +0,0 @@
-/* datetime.c - Module for common datetime function.  */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/lib/datetime.h>
-
-static char *grub_weekday_names[] =
-{
-  "Sunday",
-  "Monday",
-  "Tuesday",
-  "Wednesday",
-  "Thursday",
-  "Friday",
-  "Saturday",
-};
-
-int
-grub_get_weekday (struct grub_datetime *datetime)
-{
-  int a, y, m;
-
-  a = (14 - datetime->month) / 12;
-  y = datetime->year - a;
-  m = datetime->month + 12 * a - 2;
-
-  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
-}
-
-char *
-grub_get_weekday_name (struct grub_datetime *datetime)
-{
-  return grub_weekday_names[grub_get_weekday (datetime)];
-}
Index: fs/xfs.c
===================================================================
--- fs/xfs.c	(revision 2028)
+++ fs/xfs.c	(working copy)
@@ -620,7 +620,8 @@ grub_xfs_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_xfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_xfs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -633,14 +634,11 @@ grub_xfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/afs.c
===================================================================
--- fs/afs.c	(revision 2028)
+++ fs/afs.c	(working copy)
@@ -562,7 +562,8 @@ grub_afs_close (grub_file_t file)
 
 static grub_err_t
 grub_afs_dir (grub_device_t device, const char *path,
-              int (*hook) (const char *filename, int dir))
+              int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_afs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -575,14 +576,11 @@ grub_afs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ntfs.c
===================================================================
--- fs/ntfs.c	(revision 2028)
+++ fs/ntfs.c	(working copy)
@@ -864,7 +864,8 @@ fail:
 
 static grub_err_t
 grub_ntfs_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ntfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -877,14 +878,11 @@ grub_ntfs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/fat.c
===================================================================
--- fs/fat.c	(revision 2028)
+++ fs/fat.c	(working copy)
@@ -45,7 +45,8 @@
 				 | GRUB_FAT_ATTR_HIDDEN \
 				 | GRUB_FAT_ATTR_SYSTEM \
 				 | GRUB_FAT_ATTR_DIRECTORY \
-				 | GRUB_FAT_ATTR_ARCHIVE)
+				 | GRUB_FAT_ATTR_ARCHIVE \
+				 | GRUB_FAT_ATTR_VOLUME_ID)
 
 struct grub_fat_bpb
 {
@@ -467,51 +468,21 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
   return ret;
 }
 
-/* Find the underlying directory or file in PATH and return the
-   next path. If there is no next path or an error occurs, return NULL.
-   If HOOK is specified, call it with each file name.  */
-static char *
-grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
-		   const char *path,
-		   int (*hook) (const char *filename, int dir))
+static grub_err_t
+grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
+		      int (*hook) (const char *filename, 
+				   struct grub_fat_dir_entry *dir))
 {
   struct grub_fat_dir_entry dir;
-  char *dirname, *dirp;
   char *filename, *filep = 0;
   grub_uint16_t *unibuf;
   int slot = -1, slots = -1;
   int checksum = -1;
   grub_ssize_t offset = -sizeof(dir);
-  int call_hook;
   
   if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
-    {
-      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
-      return 0;
-    }
+    return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
   
-  /* Extract a directory name.  */
-  while (*path == '/')
-    path++;
-
-  dirp = grub_strchr (path, '/');
-  if (dirp)
-    {
-      unsigned len = dirp - path;
-      
-      dirname = grub_malloc (len + 1);
-      if (! dirname)
-	return 0;
-
-      grub_memcpy (dirname, path, len);
-      dirname[len] = '\0';
-    }
-  else
-    /* This is actually a file.  */
-    dirname = grub_strdup (path);
-
-  call_hook = (! dirp && hook);
-  
   /* Allocate space enough to hold a long name.  */
   filename = grub_malloc (0x40 * 13 * 4 + 1);
   unibuf = (grub_uint16_t *) grub_malloc (0x40 * 13 * 2);
@@ -519,7 +490,6 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
     {
       grub_free (filename);
       grub_free (unibuf);
-      grub_free (dirname);
       return 0;
     }
       
@@ -533,15 +503,8 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
       /* Read a directory entry.  */
       if ((grub_fat_read_data (disk, data, 0,
 			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno == GRUB_ERR_NONE && ! call_hook)
-	    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
-
-	  break;
-	}
-
+	   != sizeof (dir) || dir.name[0] == 0))
+	break;
       /* Handle long name entries.  */
       if (dir.attr == GRUB_FAT_ATTR_LONG_NAME)
 	{
@@ -594,22 +557,11 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 	      *grub_utf16_to_utf8 ((grub_uint8_t *) filename, unibuf,
 				   slots * 13) = '\0';
 	      
-	      if (*dirname == '\0' && call_hook)
-		{
-		  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-		    break;
-		  
-		  checksum = -1;
-		  continue;
-		}
-
-	      if (grub_strcmp (dirname, filename) == 0)
-		{
-		  if (call_hook)
-		    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
-		  
-		  break;
-		}
+	      if (hook (filename, &dir))
+		break;
+	      
+	      checksum = -1;
+	      continue;
 	    }
 
 	  checksum = -1;
@@ -617,49 +569,122 @@ grub_fat_read_data (grub_disk_t disk, struct grub_
 
       /* Convert the 8.3 file name.  */
       filep = filename;
-      
-      for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*filep++ = grub_tolower (dir.name[i]);
-      
-      *filep = '.';
-      
-      for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
-	*++filep = grub_tolower (dir.name[i]);
-
-      if (*filep != '.')
-	filep++;
-      
-      *filep = '\0';
-
-      if (*dirname == '\0' && call_hook)
+      if (dir.attr & GRUB_FAT_ATTR_VOLUME_ID)
 	{
-	  if (hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY))
-	    break;
+	  for (i = 0; i < sizeof (dir.name) && dir.name[i] 
+		 && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = dir.name[i];
 	}
-      else if (grub_strncasecmp (dirname, filename, GRUB_FAT_MAXFILE) == 0)
+      else
 	{
-	  if (call_hook)
-	    hook (filename, dir.attr & GRUB_FAT_ATTR_DIRECTORY);
+	  for (i = 0; i < 8 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *filep++ = grub_tolower (dir.name[i]);
+      
+	  *filep = '.';
+	  
+	  for (i = 8; i < 11 && dir.name[i] && ! grub_isspace (dir.name[i]); i++)
+	    *++filep = grub_tolower (dir.name[i]);
 
-	  break;
+	  if (*filep != '.')
+	    filep++;
 	}
+      *filep = '\0';
+
+      if (hook (filename, &dir))
+	break;
     }
 
   grub_free (filename);
+
+  return grub_errno;
+}
+
+
+/* Find the underlying directory or file in PATH and return the
+   next path. If there is no next path or an error occurs, return NULL.
+   If HOOK is specified, call it with each file name.  */
+static char *
+grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
+		   const char *path,
+		   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
+{
+  char *dirname, *dirp;
+  int call_hook;
+  int found = 0;
+
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    struct grub_dirhook_info info;
+    grub_memset (&info, 0, sizeof (info));
+
+    info.dir = !!(dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+    info.case_insensitive = 1;
+
+    if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
+      return 0;
+    if (*dirname == '\0' && call_hook)
+      return hook (filename, &info);
+
+    if (grub_strcasecmp (dirname, filename) == 0)
+      {
+	found = 1;
+	data->attr = dir->attr;
+	data->file_size = grub_le_to_cpu32 (dir->file_size);
+	data->file_cluster = ((grub_le_to_cpu16 (dir->first_cluster_high) << 16)
+			      | grub_le_to_cpu16 (dir->first_cluster_low));
+	data->cur_cluster_num = ~0U;
+
+	if (call_hook)
+	  hook (filename, &info);
+	    
+	return 1;
+      }
+    return 0;
+  }
+  
+  if (! (data->attr & GRUB_FAT_ATTR_DIRECTORY))
+    {
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
+      return 0;
+    }
+  
+  /* Extract a directory name.  */
+  while (*path == '/')
+    path++;
+
+  dirp = grub_strchr (path, '/');
+  if (dirp)
+    {
+      unsigned len = dirp - path;
+      
+      dirname = grub_malloc (len + 1);
+      if (! dirname)
+	return 0;
+
+      grub_memcpy (dirname, path, len);
+      dirname[len] = '\0';
+    }
+  else
+    /* This is actually a file.  */
+    dirname = grub_strdup (path);
+
+  call_hook = (! dirp && hook);
+  
+  grub_fat_iterate_dir (disk, data, iter_hook);
+  if (grub_errno == GRUB_ERR_NONE && ! found && !call_hook)
+    grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found");
+
   grub_free (dirname);
 
-  data->attr = dir.attr;
-  data->file_size = grub_le_to_cpu32 (dir.file_size);
-  data->file_cluster = ((grub_le_to_cpu16 (dir.first_cluster_high) << 16)
-			| grub_le_to_cpu16 (dir.first_cluster_low));
-  data->cur_cluster_num = ~0U;
-  
-  return dirp;
+  return found ? dirp : 0;
 }
 
 static grub_err_t
 grub_fat_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_fat_data *data = 0;
   grub_disk_t disk = device->disk;
@@ -773,8 +798,17 @@ grub_fat_label (grub_device_t device, char **label
 {
   struct grub_fat_data *data;
   grub_disk_t disk = device->disk;
-  grub_ssize_t offset = -sizeof(struct grub_fat_dir_entry);
 
+  auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
+  int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
+  {
+    if (dir->attr == GRUB_FAT_ATTR_VOLUME_ID)
+      {
+	*label = grub_strdup (filename);
+	return 1;
+      }
+    return 0;
+  }
 
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
@@ -790,37 +824,10 @@ grub_fat_label (grub_device_t device, char **label
       return 0;
     }
 
-  while (1)
-    {
-      struct grub_fat_dir_entry dir;
-
-      /* Adjust the offset.  */
-      offset += sizeof (dir);
-      
-      /* Read a directory entry.  */
-      if ((grub_fat_read_data (disk, data, 0,
-			       offset, sizeof (dir), (char *) &dir)
-	   != sizeof (dir))
-	  || dir.name[0] == 0)
-	{
-	  if (grub_errno != GRUB_ERR_NONE)
-	    goto fail;
-	  else
-	    {
-	      *label = 0;
-	      return GRUB_ERR_NONE;
-	    }
-	}
-
-      if (dir.attr == GRUB_FAT_ATTR_VOLUME_ID)
-	{
-	  *label = grub_strndup ((char *) dir.name, 11);
-	  return GRUB_ERR_NONE;
-	}
-    }
-
   *label = 0;
   
+  grub_fat_iterate_dir (disk, data, iter_hook);
+
  fail:
 
 #ifndef GRUB_UTIL
Index: fs/udf.c
===================================================================
--- fs/udf.c	(revision 2028)
+++ fs/udf.c	(working copy)
@@ -768,7 +768,8 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
 
 static grub_err_t
 grub_udf_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_udf_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -782,14 +783,11 @@ grub_udf_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
Index: fs/iso9660.c
===================================================================
--- fs/iso9660.c	(revision 2028)
+++ fs/iso9660.c	(working copy)
@@ -666,7 +666,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
 \f
 static grub_err_t
 grub_iso9660_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_iso9660_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -680,14 +681,11 @@ grub_iso9660_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/affs.c
===================================================================
--- fs/affs.c	(revision 2028)
+++ fs/affs.c	(working copy)
@@ -456,7 +456,8 @@ grub_affs_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_affs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_affs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -469,14 +470,11 @@ grub_affs_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/hfs.c
===================================================================
--- fs/hfs.c	(revision 2028)
+++ fs/hfs.c	(working copy)
@@ -960,7 +960,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, con
 \f
 static grub_err_t
 grub_hfs_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename,
+			       const struct grub_dirhook_info *info))
 {
   int inode;
 
@@ -971,13 +972,17 @@ grub_hfs_dir (grub_device_t device, const char *pa
       char fname[32] = { 0 };
       char *filetype = rec->data;
       struct grub_hfs_catalog_key *ckey = rec->key;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       grub_strncpy (fname, (char *) (ckey->str), ckey->strlen);
       
-      if (*filetype == GRUB_HFS_FILETYPE_DIR)
-	return hook (fname, 1);
-      else if (*filetype == GRUB_HFS_FILETYPE_FILE)
-	return hook (fname, 0);
+      if (*filetype == GRUB_HFS_FILETYPE_DIR 
+	  || *filetype == GRUB_HFS_FILETYPE_FILE)
+	{
+	  info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR);
+	  return hook (fname, &info);
+	}
       return 0;
     }
   
Index: fs/reiserfs.c
===================================================================
--- fs/reiserfs.c	(revision 2028)
+++ fs/reiserfs.c	(working copy)
@@ -1266,7 +1266,8 @@ grub_reiserfs_close (grub_file_t file)
 /* Call HOOK with each file under DIR.  */
 static grub_err_t
 grub_reiserfs_dir (grub_device_t device, const char *path,
-                   int (*hook) (const char *filename, int dir))
+                   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
 {
   struct grub_reiserfs_data *data = 0;
   struct grub_fshelp_node root, *found;
@@ -1280,12 +1281,11 @@ grub_reiserfs_dir (grub_device_t device, const cha
                                 enum grub_fshelp_filetype filetype,
                                 grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-        return hook (filename, 1);
-      else
-        return hook (filename, 0);
+      return hook (filename, &info);
     }
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
Index: fs/jfs.c
===================================================================
--- fs/jfs.c	(revision 2028)
+++ fs/jfs.c	(working copy)
@@ -728,7 +728,8 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *dat
 
 static grub_err_t
 grub_jfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_jfs_data *data = 0;
   struct grub_jfs_diropen *diro = 0;
@@ -752,14 +753,15 @@ grub_jfs_dir (grub_device_t device, const char *pa
   while (grub_jfs_getent (diro) != GRUB_ERR_OUT_OF_RANGE)
     {
       struct grub_jfs_inode inode;
-      int isdir;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       if (grub_jfs_read_inode (data, diro->ino, &inode))
 	goto fail;
       
-      isdir = (grub_le_to_cpu32 (inode.mode)
-	       & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
-      if (hook (diro->name, isdir))
+      info.dir = (grub_le_to_cpu32 (inode.mode)
+		  & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
+      if (hook (diro->name, &info))
 	goto fail;
     }
   
Index: fs/ext2.c
===================================================================
--- fs/ext2.c	(revision 2028)
+++ fs/ext2.c	(working copy)
@@ -788,7 +788,8 @@ grub_ext2_read (grub_file_t file, char *buf, grub_
 
 static grub_err_t
 grub_ext2_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ext2_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -801,14 +802,24 @@ grub_ext2_dir (grub_device_t device, const char *p
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      if (! node->inode_read)
+	{
+	  grub_ext2_read_inode (data, node->ino, &node->inode);
+	  if (!grub_errno)
+	    node->inode_read = 1;
+	  grub_errno = GRUB_ERR_NONE;
+	}
+      if (node->inode_read)
+	{
+	  info.mtimeset = 1;
+	  info.mtime = grub_le_to_cpu32 (node->inode.mtime);
+	}
+
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -895,6 +906,34 @@ grub_ext2_uuid (grub_device_t device, char **uuid)
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ext2_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ext2_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_le_to_cpu32 (data->sblock.utime);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_ext2_fs =
   {
@@ -905,6 +944,7 @@ static struct grub_fs grub_ext2_fs =
     .close = grub_ext2_close,
     .label = grub_ext2_label,
     .uuid = grub_ext2_uuid,
+    .mtime = grub_ext2_mtime,
     .next = 0
   };
 
Index: fs/minix.c
===================================================================
--- fs/minix.c	(revision 2028)
+++ fs/minix.c	(working copy)
@@ -461,7 +461,8 @@ grub_minix_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_minix_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_minix_data *data = 0;
   struct grub_minix_sblock *sblock;
@@ -492,6 +493,9 @@ grub_minix_dir (grub_device_t device, const char *
       grub_uint16_t ino;
       char filename[data->filename_size + 1];
       int dirino = data->ino;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+
       
       if (grub_minix_read_file (data, 0, pos, sizeof (ino),
 				(char *) &ino) < 0)
@@ -506,8 +510,9 @@ grub_minix_dir (grub_device_t device, const char *
       /* The filetype is not stored in the dirent.  Read the inode to
 	 find out the filetype.  This *REALLY* sucks.  */
       grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
-      if (hook (filename, ((GRUB_MINIX_INODE_MODE (data) 
-			    & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR)) ? 1 : 0)
+      info.dir = ((GRUB_MINIX_INODE_MODE (data) 
+		   & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
+      if (hook (filename, &info) ? 1 : 0)
 	break;
       
       /* Load the old inode back in.  */
Index: fs/hfsplus.c
===================================================================
--- fs/hfsplus.c	(revision 2028)
+++ fs/hfsplus.c	(working copy)
@@ -57,9 +57,11 @@ struct grub_hfsplus_volheader
   grub_uint16_t magic;
   grub_uint16_t version;
   grub_uint32_t attributes;
-  grub_uint8_t unused[32];
+  grub_uint8_t unused1[12];
+  grub_uint32_t utime;
+  grub_uint8_t unused2[16];
   grub_uint32_t blksize;
-  grub_uint8_t unused2[68];
+  grub_uint8_t unused3[68];
   struct grub_hfsplus_forkdata allocations_file;
   struct grub_hfsplus_forkdata extents_file;
   struct grub_hfsplus_forkdata catalog_file;
@@ -133,9 +135,11 @@ struct grub_hfsplus_catfile
   grub_uint16_t flags;
   grub_uint32_t reserved;
   grub_uint32_t fileid;
-  grub_uint8_t unused1[30];
+  grub_uint8_t unused1[4];
+  grub_uint32_t mtime;
+  grub_uint8_t unused2[22];
   grub_uint16_t mode;
-  grub_uint8_t unused2[44];
+  grub_uint8_t unused3[44];
   struct grub_hfsplus_forkdata data;
   struct grub_hfsplus_forkdata resource;
 } __attribute__ ((packed));
@@ -190,6 +194,7 @@ struct grub_fshelp_node
   struct grub_hfsplus_extent extents[8];
   grub_uint64_t size;
   grub_uint32_t fileid;
+  grub_int32_t mtime;
 };
 
 struct grub_hfsplus_btree
@@ -780,6 +785,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
 	  
 	  grub_memcpy (node->extents, fileinfo->data.extents,
 		       sizeof (node->extents));
+	  node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
 	  node->size = grub_be_to_cpu64 (fileinfo->data.size);
 	  node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
 
@@ -885,7 +891,8 @@ grub_hfsplus_read (grub_file_t file, char *buf, gr
 
 static grub_err_t
 grub_hfsplus_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_hfsplus_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -898,14 +905,14 @@ grub_hfsplus_dir (grub_device_t device, const char
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      info.mtimeset = 1;
+      info.mtime = node->mtime;
+      info.case_insensitive = !!(filetype & GRUB_FSHELP_CASE_INSENSITIVE);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -949,6 +956,34 @@ grub_hfsplus_label (grub_device_t device __attribu
 		     "partition is not implemented");
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_hfsplus_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_hfsplus_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_hfsplus_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_be_to_cpu32 (data->volheader.utime) - 2082844800;
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_hfsplus_fs =
   {
@@ -958,6 +993,7 @@ static struct grub_fs grub_hfsplus_fs =
     .read = grub_hfsplus_read,
     .close = grub_hfsplus_close,
     .label = grub_hfsplus_label,
+    .mtime = grub_hfsplus_mtime,
     .next = 0
   };
 
Index: fs/cpio.c
===================================================================
--- fs/cpio.c	(revision 2028)
+++ fs/cpio.c	(working copy)
@@ -183,7 +183,8 @@ fail:
 
 static grub_err_t
 grub_cpio_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_cpio_data *data;
   grub_uint32_t ofs;
@@ -227,7 +228,11 @@ grub_cpio_dir (grub_device_t device, const char *p
 
 	  if ((!prev) || (grub_strcmp (prev, name) != 0))
 	    {
-	      hook (name + len, p != NULL);
+	      struct grub_dirhook_info info;
+	      grub_memset (&info, 0, sizeof (info));
+	      info.dir = (p != NULL);
+
+	      hook (name + len, &info);
 	      if (prev)
 		grub_free (prev);
 	      prev = name;
Index: fs/sfs.c
===================================================================
--- fs/sfs.c	(revision 2028)
+++ fs/sfs.c	(working copy)
@@ -519,7 +519,8 @@ grub_sfs_read (grub_file_t file, char *buf, grub_s
 
 static grub_err_t
 grub_sfs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_sfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -532,14 +533,11 @@ grub_sfs_dir (grub_device_t device, const char *pa
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
Index: fs/ufs.c
===================================================================
--- fs/ufs.c	(revision 2028)
+++ fs/ufs.c	(working copy)
@@ -36,7 +36,10 @@
 #define GRUB_UFS_DIRBLKS	12
 #define GRUB_UFS_INDIRBLKS	3
 
-#define GRUB_UFS_ATTR_DIR	040000
+#define GRUB_UFS_ATTR_TYPE      0160000
+#define GRUB_UFS_ATTR_FILE	0100000
+#define GRUB_UFS_ATTR_DIR	0040000
+#define GRUB_UFS_ATTR_LNK       0120000
 
 #define GRUB_UFS_VOLNAME_LEN	32
 
@@ -51,6 +54,8 @@
                            grub_le_to_cpu##bits1 (data->inode.field) : \
                            grub_le_to_cpu##bits2 (data->inode2.field))
 #define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
+#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
+
 #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
 #define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
@@ -71,29 +76,35 @@ struct grub_ufs_sblock
   
   /* The start of the cylinder group.  */
   grub_uint32_t cylg_offset;
+  grub_uint8_t unused3[4];
+
+  grub_uint32_t mtime;
+  grub_uint8_t unused4[12];
   
-  grub_uint8_t unused3[20];
-  
   /* The size of a block in bytes.  */
   grub_int32_t bsize;
-  grub_uint8_t unused4[48];
+  grub_uint8_t unused5[48];
   
   /* The size of filesystem blocks to disk blocks.  */
   grub_uint32_t log2_blksz;
-  grub_uint8_t unused5[80];
+  grub_uint8_t unused6[80];
   
   /* Inodes stored per cylinder group.  */
   grub_uint32_t ino_per_group;
   
   /* The frags per cylinder group.  */
   grub_uint32_t frags_per_group;
+  grub_uint8_t unused7[19];
+  grub_uint8_t flags;
   
-  grub_uint8_t unused7[488];
+  grub_uint8_t unused8[468];
 
   /* Volume name for UFS2.  */
   grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
+  grub_uint8_t unused9[232];
 
-  grub_uint8_t unused8[660];
+  grub_uint64_t mtime2;
+  grub_uint8_t unused10[420];
   
   /* Magic value to check if this is really a UFS filesystem.  */
   grub_uint32_t magic;
@@ -124,7 +135,7 @@ struct grub_ufs_inode
   grub_uint32_t gen;
   grub_uint32_t unused;
   grub_uint8_t pad[12];
-};
+} __attribute__ ((packed));
 
 /* UFS inode.  */
 struct grub_ufs2_inode
@@ -160,16 +171,23 @@ struct grub_ufs2_inode
   };
 
   grub_uint8_t unused[24];
-};
+} __attribute__ ((packed));
 
 /* Directory entry.  */
 struct grub_ufs_dirent
 {
   grub_uint32_t ino;
   grub_uint16_t direntlen;
-  grub_uint8_t filetype;
-  grub_uint8_t namelen;
-};
+  union
+  {
+    grub_uint16_t namelen;
+    struct
+    {
+      grub_uint8_t filetype_bsd;
+      grub_uint8_t namelen_bsd;      
+    };
+  };
+} __attribute__ ((packed));
 
 /* Information about a "mounted" ufs filesystem.  */
 struct grub_ufs_data
@@ -225,24 +243,24 @@ grub_ufs_get_file_block (struct grub_ufs_data *dat
       return (data->ufs_type == UFS1) ? indir[blk] : indir[blk << 1];
     }
   blk -= indirsz;
-  
+
   /* Double indirect block.  */
-  if (blk < UFS_BLKSZ (sblock) / indirsz)
+  if (blk < indirsz * indirsz)
     {
       grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
       
       grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       grub_disk_read (data->disk,
-      		      (data->ufs_type == UFS1) ?
-		      indir[blk / indirsz] : indir [(blk / indirsz) << 1],
+      		      ((data->ufs_type == UFS1) ?
+		      indir[blk / indirsz] : indir [(blk / indirsz) << 1]) 
+		      << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       
       return (data->ufs_type == UFS1) ?
 	     indir[blk % indirsz] : indir[(blk % indirsz) << 1];
     }
 
-
   grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 	      "ufs does not support triple indirect blocks");
   return 0;
@@ -320,7 +338,7 @@ grub_ufs_read_file (struct grub_ufs_data *data,
 /* Read inode INO from the mounted filesystem described by DATA.  This
    inode is used by default now.  */
 static grub_err_t
-grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
+grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
 {
   struct grub_ufs_sblock *sblock = &data->sblock;
   
@@ -335,8 +353,12 @@ static grub_err_t
   
   if (data->ufs_type == UFS1)
     {
-      struct grub_ufs_inode *inode = &data->inode;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -347,8 +369,12 @@ static grub_err_t
     }
   else
     {
-      struct grub_ufs2_inode *inode = &data->inode2;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode2;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -358,7 +384,6 @@ static grub_err_t
 		      (char *) inode);
     }
   
-  data->ino = ino;
   return grub_errno;
 }
 
@@ -372,9 +397,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
   
   if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
     return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
-  
-  if (INODE_SIZE (data) < (GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS
-			  * INODE_BLKSZ (data)))
+
+  if (INODE_NBLOCKS (data) == 0)
     grub_strcpy (symlink, (char *) INODE (data, symlink));
   else
     {
@@ -390,7 +414,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *dat
     ino = GRUB_UFS_INODE;
   
   /* Now load in the old inode.  */
-  if (grub_ufs_read_inode (data, ino))
+  if (grub_ufs_read_inode (data, ino, 0))
     return grub_errno;
   
   grub_ufs_find_file (data, symlink);
@@ -433,29 +457,34 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
   do
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_strlen (name) == 0)
 	return GRUB_ERR_NONE;
       
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	return grub_errno;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
 
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  return grub_errno;
 	
-	filename[dirent.namelen] = '\0';
+	filename[namelen] = '\0';
 	
 	if (!grub_strcmp (name, filename))
 	  {
 	    dirino = data->ino;
-	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino));
-	    
-	    if (dirent.filetype == GRUB_UFS_FILETYPE_LNK)
+	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino), 0);
+
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
+		== GRUB_UFS_ATTR_LNK)
 	      {
 		grub_ufs_lookup_symlink (data, dirino);
 		if (grub_errno)
@@ -475,7 +504,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, co
 		next++;
 	      }
 	    
-	    if (!(dirent.filetype & GRUB_UFS_FILETYPE_DIR))
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 	      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 	    
 	    continue;
@@ -544,7 +573,8 @@ grub_ufs_mount (grub_disk_t disk)
 
 static grub_err_t
 grub_ufs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ufs_data *data;
   struct grub_ufs_sblock *sblock;
@@ -554,7 +584,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, GRUB_UFS_INODE);
+  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
   if (grub_errno)
     return grub_errno;
   
@@ -570,7 +600,7 @@ grub_ufs_dir (grub_device_t device, const char *pa
   if (grub_errno)
     goto fail;  
   
-  if (!(INODE_MODE (data) & GRUB_UFS_ATTR_DIR))
+  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
     {
       grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
       goto fail;
@@ -579,20 +609,45 @@ grub_ufs_dir (grub_device_t device, const char *pa
   while (pos < INODE_SIZE (data))
     {
       struct grub_ufs_dirent dirent;
-      
+      int namelen;
+
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	break;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
+	struct grub_dirhook_info info;
+	grub_memset (&info, 0, sizeof (info));
 	
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  break;
 	
-	filename[dirent.namelen] = '\0';
-	if (hook (filename, dirent.filetype == GRUB_UFS_FILETYPE_DIR))
+	filename[namelen] = '\0';
+	if (data->ufs_type == UFS1)
+	  {
+	    struct grub_ufs_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+	else
+	  {
+	    struct grub_ufs2_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+
+	if (hook (filename, &info))
 	  break;
       }
       
@@ -615,7 +670,7 @@ grub_ufs_open (struct grub_file *file, const char
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, 2);
+  grub_ufs_read_inode (data, 2, 0);
   if (grub_errno)
     {
       grub_free (data);
@@ -688,6 +743,34 @@ grub_ufs_label (grub_device_t device, char **label
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ufs_data *data = 0;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ufs_mount (device->disk);
+  if (!data)
+    *tm = 0;
+  else if (data->ufs_type == UFS1)
+    *tm = grub_le_to_cpu32 (data->sblock.mtime);
+  else
+    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+}
+
+
 \f
 static struct grub_fs grub_ufs_fs =
   {
@@ -697,6 +780,7 @@ static struct grub_fs grub_ufs_fs =
     .read = grub_ufs_read,
     .close = grub_ufs_close,
     .label = grub_ufs_label,
+    .mtime = grub_ufs_mtime,
     .next = 0
   };
 
Index: include/grub/fs.h
===================================================================
--- include/grub/fs.h	(revision 2028)
+++ include/grub/fs.h	(working copy)
@@ -27,6 +27,14 @@
 /* Forward declaration is required, because of mutual reference.  */
 struct grub_file;
 
+struct grub_dirhook_info
+{
+  int dir:1;
+  int mtimeset:1;
+  int case_insensitive:1;
+  grub_int32_t mtime;
+};
+
 /* Filesystem descriptor.  */
 struct grub_fs
 {
@@ -35,7 +43,8 @@ struct grub_fs
 
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
-		     int (*hook) (const char *filename, int dir));
+		     int (*hook) (const char *filename, 
+				  const struct grub_dirhook_info *info));
   
   /* Open a file named NAME and initialize FILE.  */
   grub_err_t (*open) (struct grub_file *file, const char *name);
@@ -56,6 +65,9 @@ struct grub_fs
      caller.  */
   grub_err_t (*uuid) (grub_device_t device, char **uuid);
 
+  /* Get writing time of filesystem. */
+  grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf);
+
   /* The next filesystem.  */
   struct grub_fs *next;
 };
Index: include/grub/fshelp.h
===================================================================
--- include/grub/fshelp.h	(revision 2028)
+++ include/grub/fshelp.h	(working copy)
@@ -27,6 +27,8 @@
 typedef struct grub_fshelp_node *grub_fshelp_node_t;
 
 #define GRUB_FSHELP_CASE_INSENSITIVE	0x100
+#define GRUB_FSHELP_TYPE_MASK	0xff
+#define GRUB_FSHELP_FLAGS_MASK	0x100
 
 enum grub_fshelp_filetype
   {
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2028)
+++ ChangeLog	(working copy)
@@ -1,3 +1,77 @@
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	UFS improvements
+
+	* fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
+	(GRUB_UFS_ATTR_FILE): likewise
+	(GRUB_UFS_ATTR_LNK): likewise
+	(GRUB_UFS_BSD_DIRENT): likewise
+	(struct grub_ufs_sblock): new fields mtime and flags
+	(struct grub_ufs_dirent): added fields for non-BSD dirents
+	(grub_ufs_get_file_block): fixed double indirect handling
+	(grub_ufs_read_inode): new parameter to read inode to a separate buffer
+	all users updated
+	(grub_ufs_find_file): support for non-BSD dirents
+	(grub_ufs_dir): likewise and mtime support
+	(grub_ufs_mtime): new function
+
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Support for mtime and further expandability of dir command
+
+	* include/grub/lib/datetime.h: moved to ...
+	* include/grub/datetime.h: ... moved here and added 
+	declaration of grub_unixtime2datetime. All users updated
+	* include/grub/fs.h: new syntax for dir and mtime functionin 
+	struct grub_fs 
+	* include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
+	and GRUB_FSHELP_FLAGS_MASK
+	* commands/ls.c (grub_ls_list_files): Write mtime in long format
+	* fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
+	(grub_ext2_mtime): new function
+	* fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply mtime
+	(grub_hfsplus_mtime): new function
+	* fs/affs.c (grub_affs_dir): use new dir syntax
+	* fs/afs.c (grub_afs_dir): likewise
+	* fs/cpio.c (grub_cpio_dir): likewise
+	* fs/fat.c (grub_fat_find_dir): likewise
+	* fs/hfs.c (grub_hfs_dir): likewise
+	* fs/iso9660.c (grub_iso9660_dir): likewise
+	* fs/jfs.c (grub_jfs_dir): likewise
+	* fs/minix.c (grub_minix_dir): likewise
+	* fs/ntfs.c (grub_ntfs_dir): likewise
+	* fs/reiserfs.c (grub_reiserfs_dir): likewise
+	* fs/sfs.c (grub_sfs_dir): likewise
+	* fs/xfs.c (grub_xfs_dir): likewise
+	* fs/ufs.c (grub_ufs_dir): likewise
+	* util/hostfs.c (grub_hostfs_dir): likewise
+	* lib/datetime.c: moved to ...
+	* normal/datetime.c: ... moved here
+	(grub_unixtime2datetime): new function
+	* kern/rescue.c (grub_rescue_print_files): use new dir syntax
+	* normal/completition.c (iterate_dir): use new dir syntax
+	* normal/misc.c (grub_normal_print_device_info): tell the 
+	last modification time of a volume
+	* kern/fs.c (grub_fs_probe): updated dummy function to use new syntax 
+	* conf/common.rmk: added lib/datetime.c to ls.mod
+	* conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu 
+	and normal.mod. Removed lib/datetime.c from datetime.mod
+	* conf/i386-efi.rmk: likewise
+	* conf/i386-ieee1275.rmk: likewise	
+	* conf/i386-pc.rmk: likewise
+	* conf/powerpc-ieee1275.rmk: likewise
+	* conf/sparc64-ieee1275.rmk: likewise	
+	* conf/x86_64-efi.rmk: likewise	
+ 	
+2009-03-11  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Trim trailing spaces in FAT label and support mtools-like labels
+	
+	* fs/fat.c (grub_fat_iterate_dir): New function based 
+	on grub_fat_find_dir
+	(grub_fat_find_dir): use grub_fat_iterate_dir
+	(grub_fat_label): likewise 
+
 2009-03-11  Pavel Roskin  <proski@gnu.org>
 
 	* fs/hfs.c (grub_hfs_strncasecmp): New function.
Index: normal/completion.c
===================================================================
--- normal/completion.c	(revision 2028)
+++ normal/completion.c	(working copy)
@@ -123,9 +123,9 @@ iterate_partition (grub_disk_t disk, const grub_pa
 }
 
 static int
-iterate_dir (const char *filename, int dir)
+iterate_dir (const char *filename, const struct grub_dirhook_info *info)
 {
-  if (! dir)
+  if (! info->dir)
     {
       const char *prefix;
       if (cmdline_state == GRUB_PARSER_STATE_DQUOTE)
Index: normal/misc.c
===================================================================
--- normal/misc.c	(revision 2028)
+++ normal/misc.c	(working copy)
@@ -23,6 +23,7 @@
 #include <grub/err.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/datetime.h>
 
 /* Print the information on the device NAME.  */
 grub_err_t
@@ -63,6 +64,23 @@ grub_normal_print_device_info (const char *name)
 		}
 	      grub_errno = GRUB_ERR_NONE;
 	    }
+	  if (fs->mtime)
+	    {
+	      grub_int32_t tm;
+	      struct grub_datetime datetime;
+	      (fs->mtime) (dev, &tm);
+	      if (grub_errno == GRUB_ERR_NONE)
+		{
+		  grub_unixtime2datetime (tm, &datetime);
+		  grub_printf (", Last modification time %d-%02d-%02d "
+			       "%02d:%02d:%02d %s",
+			       datetime.year, datetime.month, datetime.day,
+			       datetime.hour, datetime.minute, datetime.second,
+			       grub_get_weekday_name (&datetime));
+
+		}
+	      grub_errno = GRUB_ERR_NONE;
+	    }
 	  if (fs->uuid)
 	    {
 	      char *uuid;
Index: normal/datetime.c
===================================================================
--- normal/datetime.c	(revision 0)
+++ normal/datetime.c	(revision 0)
@@ -0,0 +1,100 @@
+/* datetime.c - Module for common datetime function.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/datetime.h>
+
+static char *grub_weekday_names[] =
+{
+  "Sunday",
+  "Monday",
+  "Tuesday",
+  "Wednesday",
+  "Thursday",
+  "Friday",
+  "Saturday",
+};
+
+int
+grub_get_weekday (struct grub_datetime *datetime)
+{
+  int a, y, m;
+
+  a = (14 - datetime->month) / 12;
+  y = datetime->year - a;
+  m = datetime->month + 12 * a - 2;
+
+  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
+}
+
+char *
+grub_get_weekday_name (struct grub_datetime *datetime)
+{
+  return grub_weekday_names[grub_get_weekday (datetime)];
+}
+
+#define SECPERMIN 60
+#define SECPERHOUR (60*SECPERMIN)
+#define SECPERDAY (24*SECPERHOUR)
+#define SECPERYEAR (365*SECPERDAY)
+#define SECPER4YEARS (4*SECPERYEAR+SECPERDAY)
+
+
+void
+grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime)
+{
+  int i;
+  int div;
+  grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 
+  /* In the period of validity of unixtime all years divisible by 4 
+     are bissextile*/
+  /* Convenience: let's have 3 consecutive non-bissextile years 
+     at the begining of the epoch. So count from 1973 instead of 1970 */
+  nix -= 3*SECPERYEAR + SECPERDAY;
+  /* Transform C divisions and modulos to mathematical ones */
+  div = nix / SECPER4YEARS;
+  if (nix < 0)
+    div--;
+  datetime->year = 1973 + 4 * div;
+  nix -= div * SECPER4YEARS;
+
+  /* On 31st december of bissextile years 365 days from the begining 
+     of the year elapsed but year isn't finished yet*/
+  if (nix / SECPERYEAR == 4)
+    {
+      datetime->year += 3;
+      nix -= 3*SECPERYEAR;
+    }
+  else
+    {
+      datetime->year += nix / SECPERYEAR;
+      nix %= SECPERYEAR;
+    }
+  for (i = 0; i < 12 
+	 && nix >= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+				    ? 29 : months[i]))*SECPERDAY; i++)
+    nix -= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+			    ? 29 : months[i]))*SECPERDAY;
+  datetime->month = i + 1; 
+  datetime->day = 1 + (nix / SECPERDAY);
+  nix %= SECPERDAY;
+  datetime->hour = (nix / SECPERHOUR);  
+  nix %= SECPERHOUR;
+  datetime->minute = nix / SECPERMIN;
+  datetime->second = nix % SECPERMIN;
+}
Index: commands/date.c
===================================================================
--- commands/date.c	(revision 2028)
+++ commands/date.c	(working copy)
@@ -22,7 +22,7 @@
 #include <grub/arg.h>
 #include <grub/err.h>
 #include <grub/misc.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 #define GRUB_DATETIME_SET_YEAR		1
 #define GRUB_DATETIME_SET_MONTH		2
Index: commands/ls.c
===================================================================
--- commands/ls.c	(revision 2028)
+++ commands/ls.c	(working copy)
@@ -29,6 +29,7 @@
 #include <grub/term.h>
 #include <grub/partition.h>
 #include <grub/file.h>
+#include <grub/datetime.h>
 
 static const struct grub_arg_option options[] =
   {
@@ -68,25 +69,29 @@ grub_ls_list_files (char *dirname, int longlist, i
   grub_fs_t fs;
   const char *path;
   grub_device_t dev;
-  auto int print_files (const char *filename, int dir);
-  auto int print_files_long (const char *filename, int dir);
+
+  auto int print_files (const char *filename, 
+			const struct grub_dirhook_info *info);
+  auto int print_files_long (const char *filename, 
+			     const struct grub_dirhook_info *info);
   
-  int print_files (const char *filename, int dir)
+  int print_files (const char *filename, const struct grub_dirhook_info *info)
     {
       if (all || filename[0] != '.')
-	grub_printf ("%s%s ", filename, dir ? "/" : "");
+	grub_printf ("%s%s ", filename, info->dir ? "/" : "");
       
       return 0;
     }
      
-  int print_files_long (const char *filename, int dir)
+  int print_files_long (const char *filename, 
+			const struct grub_dirhook_info *info)
     {
       char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1];
 
       if ((! all) && (filename[0] == '.'))
 	return 0;
 
-      if (! dir)
+      if (! info->dir)
 	{
 	  grub_file_t file;
 	  
@@ -138,7 +143,23 @@ grub_ls_list_files (char *dirname, int longlist, i
       else
 	grub_printf ("%-12s", "DIR");
 
-      grub_printf ("%s%s\n", filename, dir ? "/" : "");
+      if (info->mtimeset)
+	{
+	  struct grub_datetime datetime;
+	  grub_unixtime2datetime (info->mtime, &datetime);
+	  if (human)
+	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
+			 datetime.year, datetime.month, datetime.day,
+			 datetime.hour, datetime.minute, 
+			 datetime.second,
+			 grub_get_weekday_name (&datetime));
+	  else
+	    grub_printf (" %04d%02d%02d%02d%02d%02d ",
+			 datetime.year, datetime.month, 
+			 datetime.day, datetime.hour, 
+			 datetime.minute, datetime.second);
+	}
+      grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
 
       return 0;
     }
@@ -181,7 +202,7 @@ grub_ls_list_files (char *dirname, int longlist, i
 	  /* PATH might be a regular file.  */
 	  char *p;
 	  grub_file_t file;
-
+	  struct grub_dirhook_info info;
 	  grub_errno = 0;
 	  
 	  file = grub_file_open (dirname);
@@ -196,10 +217,11 @@ grub_ls_list_files (char *dirname, int longlist, i
 	    goto fail;
 
 	  all = 1;
+	  grub_memset (&info, 0, sizeof (info));
 	  if (longlist)
-	    print_files_long (p, 0);
+	    print_files_long (p, &info);
 	  else
-	    print_files (p, 0);
+	    print_files (p, &info);
 
 	  grub_free (dirname);
 	}
Index: util/hostfs.c
===================================================================
--- util/hostfs.c	(revision 2028)
+++ util/hostfs.c	(working copy)
@@ -16,7 +16,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
-
+#define _BSD_SOURCE
 #include <grub/fs.h>
 #include <grub/file.h>
 #include <grub/disk.h>
@@ -57,7 +57,8 @@ is_dir (const char *path, const char *name)
 
 static grub_err_t
 grub_hostfs_dir (grub_device_t device, const char *path, 
-		 int (*hook) (const char *filename, int dir))
+		 int (*hook) (const char *filename, 
+			      const struct grub_dirhook_info *info))
 {
   DIR *dir;
 
@@ -73,16 +74,20 @@ grub_hostfs_dir (grub_device_t device, const char
   while (1)
     {
       struct dirent *de;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
 
       de = readdir (dir);
       if (! de)
 	break;
 
 #ifdef DT_DIR
-      hook (de->d_name, de->d_type == DT_DIR);
+      info.dir = (de->d_type == DT_DIR);
 #else
-      hook (de->d_name, is_dir (path, de->d_name));
+      info.dir = !!is_dir (path, de->d_name);
 #endif
+      hook (de->d_name, &info);
+
     }
 
   closedir (dir);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-01 16:25 [PATCH] FAT, UFS and mtime phcoder
  2009-03-01 19:13 ` Bean
  2009-03-11 21:32 ` phcoder
@ 2009-03-13 19:10 ` Robert Millan
  2009-03-15  0:34   ` phcoder
  2009-03-15 11:16   ` phcoder
  2 siblings, 2 replies; 12+ messages in thread
From: Robert Millan @ 2009-03-13 19:10 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Mar 01, 2009 at 05:25:10PM +0100, phcoder wrote:
> Hello all. It seems that gcc has trouble with -m32 when structure is  
> passed as argument. So I replaced that part by a pointer. Also I made  
> some improvements to ufs code to support solaris branch of ufs. I tested  
> it also with freebsd and netbsd's branch and it works fine on it too.
> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a  
> patch with all 3 features. If it's really necessary I can split them but  
> it requires a lot of unnecessary work

Please do.  It is definitely confusing to review patches that merge
unrelated things.

Also, please don't include the changelog entry in your patch, since those
break too easily.  Just paste it at the top of your mail.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-13 19:10 ` Robert Millan
@ 2009-03-15  0:34   ` phcoder
  2009-04-04  9:21     ` phcoder
  2009-03-15 11:16   ` phcoder
  1 sibling, 1 reply; 12+ messages in thread
From: phcoder @ 2009-03-15  0:34 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 3159 bytes --]

mtime part
2009-03-15  Vladimir Serbinenko  <phcoder@gmail.com>

	Support for mtime and further expandability of dir command

	* include/grub/lib/datetime.h: moved to ...
	* include/grub/datetime.h: ... moved here and added
	declaration of grub_unixtime2datetime. All users updated
	* include/grub/fs.h: new syntax for dir and mtime functionin
	struct grub_fs
	* include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
	and GRUB_FSHELP_FLAGS_MASK
	* commands/ls.c (grub_ls_list_files): Write mtime in long format
	* fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
	(grub_ext2_mtime): new function
	* fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply mtime
	(grub_hfsplus_mtime): new function
	* fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
	(GRUB_UFS_ATTR_FILE): likewise
	(GRUB_UFS_ATTR_LNK): likewise
	(struct grub_ufs_sblock): new fields mtime
	(grub_ufs_read_inode): new parameter to read inode to a separate buffer
	all users updated
	(grub_ufs_dir): mtime support
	(grub_ufs_mtime): new function
	* fs/affs.c (grub_affs_dir): use new dir syntax
	* fs/afs.c (grub_afs_dir): likewise
	* fs/cpio.c (grub_cpio_dir): likewise
	* fs/fat.c (grub_fat_find_dir): likewise
	* fs/hfs.c (grub_hfs_dir): likewise
	* fs/iso9660.c (grub_iso9660_dir): likewise
	* fs/jfs.c (grub_jfs_dir): likewise
	* fs/minix.c (grub_minix_dir): likewise
	* fs/ntfs.c (grub_ntfs_dir): likewise
	* fs/reiserfs.c (grub_reiserfs_dir): likewise
	* fs/sfs.c (grub_sfs_dir): likewise
	* fs/xfs.c (grub_xfs_dir): likewise
	* util/hostfs.c (grub_hostfs_dir): likewise
	* lib/datetime.c: moved to ...
	* normal/datetime.c: ... moved here
	(grub_unixtime2datetime): new function
	* kern/rescue.c (grub_rescue_print_files): use new dir syntax
	* normal/completition.c (iterate_dir): use new dir syntax
	* normal/misc.c (grub_normal_print_device_info): tell the
	last modification time of a volume
	* kern/fs.c (grub_fs_probe): updated dummy function to use new syntax
	* conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu
	and normal.mod. Removed lib/datetime.c from datetime.mod
	* conf/i386-efi.rmk: likewise
	* conf/i386-ieee1275.rmk: likewise	
	* conf/i386-pc.rmk: likewise
	* conf/powerpc-ieee1275.rmk: likewise
	* conf/sparc64-ieee1275.rmk: likewise	
	* conf/x86_64-efi.rmk: likewise	
  	

Robert Millan wrote:
> On Sun, Mar 01, 2009 at 05:25:10PM +0100, phcoder wrote:
>> Hello all. It seems that gcc has trouble with -m32 when structure is  
>> passed as argument. So I replaced that part by a pointer. Also I made  
>> some improvements to ufs code to support solaris branch of ufs. I tested  
>> it also with freebsd and netbsd's branch and it works fine on it too.
>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a  
>> patch with all 3 features. If it's really necessary I can split them but  
>> it requires a lot of unnecessary work
> 
> Please do.  It is definitely confusing to review patches that merge
> unrelated things.
> 
> Also, please don't include the changelog entry in your patch, since those
> break too easily.  Just paste it at the top of your mail.
> 


-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: mtime.diff --]
[-- Type: text/x-diff, Size: 54007 bytes --]

--- a/commands/date.c
+++ b/commands/date.c
@@ -22,7 +22,7 @@
 #include <grub/arg.h>
 #include <grub/err.h>
 #include <grub/misc.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 #define GRUB_DATETIME_SET_YEAR		1
 #define GRUB_DATETIME_SET_MONTH		2
diff --git a/commands/ls.c b/commands/ls.c
index 7f5a609..66a34c2 100644
--- a/commands/ls.c
+++ b/commands/ls.c
@@ -29,6 +29,7 @@
 #include <grub/term.h>
 #include <grub/partition.h>
 #include <grub/file.h>
+#include <grub/datetime.h>
 
 static const struct grub_arg_option options[] =
   {
@@ -68,25 +69,29 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
   grub_fs_t fs;
   const char *path;
   grub_device_t dev;
-  auto int print_files (const char *filename, int dir);
-  auto int print_files_long (const char *filename, int dir);
+
+  auto int print_files (const char *filename, 
+			const struct grub_dirhook_info *info);
+  auto int print_files_long (const char *filename, 
+			     const struct grub_dirhook_info *info);
   
-  int print_files (const char *filename, int dir)
+  int print_files (const char *filename, const struct grub_dirhook_info *info)
     {
       if (all || filename[0] != '.')
-	grub_printf ("%s%s ", filename, dir ? "/" : "");
+	grub_printf ("%s%s ", filename, info->dir ? "/" : "");
       
       return 0;
     }
      
-  int print_files_long (const char *filename, int dir)
+  int print_files_long (const char *filename, 
+			const struct grub_dirhook_info *info)
     {
       char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1];
 
       if ((! all) && (filename[0] == '.'))
 	return 0;
 
-      if (! dir)
+      if (! info->dir)
 	{
 	  grub_file_t file;
 	  
@@ -138,7 +143,23 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
       else
 	grub_printf ("%-12s", "DIR");
 
-      grub_printf ("%s%s\n", filename, dir ? "/" : "");
+      if (info->mtimeset)
+	{
+	  struct grub_datetime datetime;
+	  grub_unixtime2datetime (info->mtime, &datetime);
+	  if (human)
+	    grub_printf (" %d-%02d-%02d %02d:%02d:%02d %-11s ",
+			 datetime.year, datetime.month, datetime.day,
+			 datetime.hour, datetime.minute, 
+			 datetime.second,
+			 grub_get_weekday_name (&datetime));
+	  else
+	    grub_printf (" %04d%02d%02d%02d%02d%02d ",
+			 datetime.year, datetime.month, 
+			 datetime.day, datetime.hour, 
+			 datetime.minute, datetime.second);
+	}
+      grub_printf ("%s%s\n", filename, info->dir ? "/" : "");
 
       return 0;
     }
@@ -181,7 +202,7 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
 	  /* PATH might be a regular file.  */
 	  char *p;
 	  grub_file_t file;
-
+	  struct grub_dirhook_info info;
 	  grub_errno = 0;
 	  
 	  file = grub_file_open (dirname);
@@ -196,10 +217,11 @@ grub_ls_list_files (char *dirname, int longlist, int all, int human)
 	    goto fail;
 
 	  all = 1;
+	  grub_memset (&info, 0, sizeof (info));
 	  if (longlist)
-	    print_files_long (p, 0);
+	    print_files_long (p, &info);
 	  else
-	    print_files (p, 0);
+	    print_files (p, &info);
 
 	  grub_free (dirname);
 	}
diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
index e68bed3..33b798c 100644
--- a/conf/i386-coreboot.rmk
+++ b/conf/i386-coreboot.rmk
@@ -75,6 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/completion.c normal/main.c normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
@@ -121,7 +123,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -192,7 +194,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
index 1c372cd..f9380d1 100644
--- a/conf/i386-efi.rmk
+++ b/conf/i386-efi.rmk
@@ -52,7 +52,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c 		\
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -119,7 +120,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genke
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -177,7 +178,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
index 089055c..1bd3e4e 100644
--- a/conf/i386-ieee1275.rmk
+++ b/conf/i386-ieee1275.rmk
@@ -75,7 +75,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/menu_text.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/menu_text.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
@@ -112,7 +113,7 @@ pkglib_MODULES = normal.mod halt.mod reboot.mod suspend.mod		\
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -192,7 +193,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index c996e45..a2fca47 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -128,7 +128,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/main.c normal/color.c		\
+	normal/completion.c normal/datetime.c normal/main.c 		\
+	normal/color.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -209,7 +210,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c  normal/execute.c		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -351,7 +352,7 @@ pxecmd_mod_CFLAGS = $(COMMON_CFLAGS)
 pxecmd_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/i386/datetime.c
+datetime_mod_SOURCES = lib/i386/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
index efa59c0..f33d19a 100644
--- a/conf/powerpc-ieee1275.rmk
+++ b/conf/powerpc-ieee1275.rmk
@@ -56,7 +56,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
 	kern/misc.c kern/parser.c kern/partition.c kern/rescue.c	\
 	kern/term.c kern/list.c kern/handler.c fs/fshelp.c		\
 	normal/arg.c normal/cmdline.c normal/command.c			\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c 	\
 	normal/menu_text.c						\
 	normal/menu_entry.c normal/menu_viewer.c normal/misc.c 		\
@@ -133,7 +133,7 @@ linux_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk
index 1658a66..75cc1f4 100644
--- a/conf/sparc64-ieee1275.rmk
+++ b/conf/sparc64-ieee1275.rmk
@@ -57,7 +57,8 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-mkimage.c util/misc.c \
 #	kern/parser.c kern/partition.c kern/rescue.c kern/term.c	\
 #	kern/list.c kern/handler.c					\
 #	normal/arg.c normal/cmdline.c normal/command.c			\
-#	normal/completion.c normal/context.c normal/execute.c		\
+#	normal/completion.c normal/datetime.c normal/context.c		\
+#	normal/execute.c		\
 #	normal/function.c normal/lexer.c				\
 #	normal/main.c normal/menu.c normal/menu_entry.c			\
 #	normal/menu_text.c						\
@@ -166,7 +167,7 @@ sfs_mod_LDFLAGS = $(COMMON_LDFLAGS)
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
index 47132f7..ebbfb23 100644
--- a/conf/x86_64-efi.rmk
+++ b/conf/x86_64-efi.rmk
@@ -54,7 +54,8 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
 	kern/loader.c kern/main.c kern/misc.c kern/parser.c		\
 	grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c	\
 	normal/arg.c normal/cmdline.c normal/command.c normal/function.c\
-	normal/completion.c normal/context.c normal/main.c		\
+	normal/completion.c normal/datetime.c normal/context.c \
+	normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/menu_text.c						\
 	normal/misc.c normal/script.c					\
@@ -121,7 +122,7 @@ kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genke
 # keep it simpler to update to different architectures.
 #
 normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c	\
-	normal/completion.c normal/execute.c		 		\
+	normal/completion.c normal/datetime.c normal/execute.c 		\
 	normal/function.c normal/lexer.c normal/main.c normal/menu.c	\
 	normal/menu_text.c						\
 	normal/color.c							\
@@ -179,7 +180,7 @@ lspci_mod_CFLAGS = $(COMMON_CFLAGS)
 lspci_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
 # For datetime.mod
-datetime_mod_SOURCES = lib/datetime.c lib/efi/datetime.c
+datetime_mod_SOURCES = lib/efi/datetime.c
 datetime_mod_CFLAGS = $(COMMON_CFLAGS)
 datetime_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
diff --git a/fs/affs.c b/fs/affs.c
index bc7bc21..4ddc347 100644
--- a/fs/affs.c
+++ b/fs/affs.c
@@ -456,7 +456,8 @@ grub_affs_read (grub_file_t file, char *buf, grub_size_t len)
 
 static grub_err_t
 grub_affs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_affs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -469,14 +470,11 @@ grub_affs_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
diff --git a/fs/afs.c b/fs/afs.c
index 3f7efa7..90d8864 100644
--- a/fs/afs.c
+++ b/fs/afs.c
@@ -562,7 +562,8 @@ grub_afs_close (grub_file_t file)
 
 static grub_err_t
 grub_afs_dir (grub_device_t device, const char *path,
-              int (*hook) (const char *filename, int dir))
+              int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_afs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -575,14 +576,11 @@ grub_afs_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
diff --git a/fs/cpio.c b/fs/cpio.c
index 3d8078a..bedd65e 100644
--- a/fs/cpio.c
+++ b/fs/cpio.c
@@ -183,7 +183,8 @@ fail:
 
 static grub_err_t
 grub_cpio_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_cpio_data *data;
   grub_uint32_t ofs;
@@ -227,7 +228,11 @@ grub_cpio_dir (grub_device_t device, const char *path,
 
 	  if ((!prev) || (grub_strcmp (prev, name) != 0))
 	    {
-	      hook (name + len, p != NULL);
+	      struct grub_dirhook_info info;
+	      grub_memset (&info, 0, sizeof (info));
+	      info.dir = (p != NULL);
+
+	      hook (name + len, &info);
 	      if (prev)
 		grub_free (prev);
 	      prev = name;
diff --git a/fs/ext2.c b/fs/ext2.c
index ac0757e..d3d0508 100644
--- a/fs/ext2.c
+++ b/fs/ext2.c
@@ -788,7 +788,8 @@ grub_ext2_read (grub_file_t file, char *buf, grub_size_t len)
 
 static grub_err_t
 grub_ext2_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ext2_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -801,14 +802,24 @@ grub_ext2_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      if (! node->inode_read)
+	{
+	  grub_ext2_read_inode (data, node->ino, &node->inode);
+	  if (!grub_errno)
+	    node->inode_read = 1;
+	  grub_errno = GRUB_ERR_NONE;
+	}
+      if (node->inode_read)
+	{
+	  info.mtimeset = 1;
+	  info.mtime = grub_le_to_cpu32 (node->inode.mtime);
+	}
+
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -895,6 +906,34 @@ grub_ext2_uuid (grub_device_t device, char **uuid)
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ext2_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ext2_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ext2_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_le_to_cpu32 (data->sblock.utime);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_ext2_fs =
   {
@@ -905,6 +944,7 @@ static struct grub_fs grub_ext2_fs =
     .close = grub_ext2_close,
     .label = grub_ext2_label,
     .uuid = grub_ext2_uuid,
+    .mtime = grub_ext2_mtime,
     .next = 0
   };
 
diff --git a/fs/fat.c b/fs/fat.c
index d9b0fe1..925cff2 100644
--- a/fs/fat.c
+++ b/fs/fat.c
@@ -606,7 +606,8 @@ grub_fat_iterate_dir (grub_disk_t disk, struct grub_fat_data *data,
 static char *
 grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
 		   const char *path,
-		   int (*hook) (const char *filename, int dir))
+		   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
 {
   char *dirname, *dirp;
   int call_hook;
@@ -615,10 +616,16 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
   auto int iter_hook (const char *filename, struct grub_fat_dir_entry *dir);
   int iter_hook (const char *filename, struct grub_fat_dir_entry *dir)
   {
+    struct grub_dirhook_info info;
+    grub_memset (&info, 0, sizeof (info));
+
+    info.dir = !!(dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+    info.case_insensitive = 1;
+
     if (dir->attr & GRUB_FAT_ATTR_VOLUME_ID)
       return 0;
     if (*dirname == '\0' && call_hook)
-      return hook (filename, dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+      return hook (filename, &info);
 
     if (grub_strcasecmp (dirname, filename) == 0)
       {
@@ -630,7 +637,7 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
 	data->cur_cluster_num = ~0U;
 
 	if (call_hook)
-	  hook (filename, dir->attr & GRUB_FAT_ATTR_DIRECTORY);
+	  hook (filename, &info);
 	    
 	return 1;
       }
@@ -676,7 +683,8 @@ grub_fat_find_dir (grub_disk_t disk, struct grub_fat_data *data,
 
 static grub_err_t
 grub_fat_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_fat_data *data = 0;
   grub_disk_t disk = device->disk;
diff --git a/fs/hfs.c b/fs/hfs.c
index a923309..55dfbfd 100644
--- a/fs/hfs.c
+++ b/fs/hfs.c
@@ -960,7 +960,8 @@ grub_hfs_find_dir (struct grub_hfs_data *data, const char *path,
 \f
 static grub_err_t
 grub_hfs_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename,
+			       const struct grub_dirhook_info *info))
 {
   int inode;
 
@@ -971,13 +972,17 @@ grub_hfs_dir (grub_device_t device, const char *path,
       char fname[32] = { 0 };
       char *filetype = rec->data;
       struct grub_hfs_catalog_key *ckey = rec->key;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       grub_strncpy (fname, (char *) (ckey->str), ckey->strlen);
       
-      if (*filetype == GRUB_HFS_FILETYPE_DIR)
-	return hook (fname, 1);
-      else if (*filetype == GRUB_HFS_FILETYPE_FILE)
-	return hook (fname, 0);
+      if (*filetype == GRUB_HFS_FILETYPE_DIR 
+	  || *filetype == GRUB_HFS_FILETYPE_FILE)
+	{
+	  info.dir = (*filetype == GRUB_HFS_FILETYPE_DIR);
+	  return hook (fname, &info);
+	}
       return 0;
     }
   
diff --git a/fs/hfsplus.c b/fs/hfsplus.c
index 7022f98..6f80094 100644
--- a/fs/hfsplus.c
+++ b/fs/hfsplus.c
@@ -57,9 +57,11 @@ struct grub_hfsplus_volheader
   grub_uint16_t magic;
   grub_uint16_t version;
   grub_uint32_t attributes;
-  grub_uint8_t unused[32];
+  grub_uint8_t unused1[12];
+  grub_uint32_t utime;
+  grub_uint8_t unused2[16];
   grub_uint32_t blksize;
-  grub_uint8_t unused2[68];
+  grub_uint8_t unused3[68];
   struct grub_hfsplus_forkdata allocations_file;
   struct grub_hfsplus_forkdata extents_file;
   struct grub_hfsplus_forkdata catalog_file;
@@ -133,9 +135,11 @@ struct grub_hfsplus_catfile
   grub_uint16_t flags;
   grub_uint32_t reserved;
   grub_uint32_t fileid;
-  grub_uint8_t unused1[30];
+  grub_uint8_t unused1[4];
+  grub_uint32_t mtime;
+  grub_uint8_t unused2[22];
   grub_uint16_t mode;
-  grub_uint8_t unused2[44];
+  grub_uint8_t unused3[44];
   struct grub_hfsplus_forkdata data;
   struct grub_hfsplus_forkdata resource;
 } __attribute__ ((packed));
@@ -190,6 +194,7 @@ struct grub_fshelp_node
   struct grub_hfsplus_extent extents[8];
   grub_uint64_t size;
   grub_uint32_t fileid;
+  grub_int32_t mtime;
 };
 
 struct grub_hfsplus_btree
@@ -780,6 +785,7 @@ grub_hfsplus_iterate_dir (grub_fshelp_node_t dir,
 	  
 	  grub_memcpy (node->extents, fileinfo->data.extents,
 		       sizeof (node->extents));
+	  node->mtime = grub_be_to_cpu32 (fileinfo->mtime) - 2082844800;
 	  node->size = grub_be_to_cpu64 (fileinfo->data.size);
 	  node->fileid = grub_be_to_cpu32 (fileinfo->fileid);
 
@@ -885,7 +891,8 @@ grub_hfsplus_read (grub_file_t file, char *buf, grub_size_t len)
 
 static grub_err_t
 grub_hfsplus_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_hfsplus_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -898,14 +905,14 @@ grub_hfsplus_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      info.mtimeset = 1;
+      info.mtime = node->mtime;
+      info.case_insensitive = !!(filetype & GRUB_FSHELP_CASE_INSENSITIVE);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
@@ -949,6 +956,34 @@ grub_hfsplus_label (grub_device_t device __attribute__((unused))
 		     "partition is not implemented");
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_hfsplus_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_hfsplus_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_hfsplus_mount (disk);
+  if (!data)
+    *tm = 0;
+  else 
+    *tm = grub_be_to_cpu32 (data->volheader.utime) - 2082844800;
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+
+}
+
+
 \f
 static struct grub_fs grub_hfsplus_fs =
   {
@@ -958,6 +993,7 @@ static struct grub_fs grub_hfsplus_fs =
     .read = grub_hfsplus_read,
     .close = grub_hfsplus_close,
     .label = grub_hfsplus_label,
+    .mtime = grub_hfsplus_mtime,
     .next = 0
   };
 
diff --git a/fs/iso9660.c b/fs/iso9660.c
index 6db2283..2278fdc 100644
--- a/fs/iso9660.c
+++ b/fs/iso9660.c
@@ -666,7 +666,8 @@ grub_iso9660_iterate_dir (grub_fshelp_node_t dir,
 \f
 static grub_err_t
 grub_iso9660_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_iso9660_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -680,14 +681,11 @@ grub_iso9660_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
diff --git a/fs/jfs.c b/fs/jfs.c
index fc9dab8..3b5520f 100644
--- a/fs/jfs.c
+++ b/fs/jfs.c
@@ -728,7 +728,8 @@ grub_jfs_lookup_symlink (struct grub_jfs_data *data, int ino)
 
 static grub_err_t
 grub_jfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_jfs_data *data = 0;
   struct grub_jfs_diropen *diro = 0;
@@ -752,14 +753,15 @@ grub_jfs_dir (grub_device_t device, const char *path,
   while (grub_jfs_getent (diro) != GRUB_ERR_OUT_OF_RANGE)
     {
       struct grub_jfs_inode inode;
-      int isdir;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
       
       if (grub_jfs_read_inode (data, diro->ino, &inode))
 	goto fail;
       
-      isdir = (grub_le_to_cpu32 (inode.mode)
-	       & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
-      if (hook (diro->name, isdir))
+      info.dir = (grub_le_to_cpu32 (inode.mode)
+		  & GRUB_JFS_FILETYPE_MASK) == GRUB_JFS_FILETYPE_DIR;
+      if (hook (diro->name, &info))
 	goto fail;
     }
   
diff --git a/fs/minix.c b/fs/minix.c
index cc03d7d..0789718 100644
--- a/fs/minix.c
+++ b/fs/minix.c
@@ -461,7 +461,8 @@ grub_minix_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_minix_dir (grub_device_t device, const char *path, 
-		  int (*hook) (const char *filename, int dir))
+		  int (*hook) (const char *filename, 
+			       const struct grub_dirhook_info *info))
 {
   struct grub_minix_data *data = 0;
   struct grub_minix_sblock *sblock;
@@ -492,6 +493,9 @@ grub_minix_dir (grub_device_t device, const char *path,
       grub_uint16_t ino;
       char filename[data->filename_size + 1];
       int dirino = data->ino;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+
       
       if (grub_minix_read_file (data, 0, pos, sizeof (ino),
 				(char *) &ino) < 0)
@@ -506,8 +510,9 @@ grub_minix_dir (grub_device_t device, const char *path,
       /* The filetype is not stored in the dirent.  Read the inode to
 	 find out the filetype.  This *REALLY* sucks.  */
       grub_minix_read_inode (data, grub_le_to_cpu16 (ino));
-      if (hook (filename, ((GRUB_MINIX_INODE_MODE (data) 
-			    & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR)) ? 1 : 0)
+      info.dir = ((GRUB_MINIX_INODE_MODE (data) 
+		   & GRUB_MINIX_IFDIR) == GRUB_MINIX_IFDIR);
+      if (hook (filename, &info) ? 1 : 0)
 	break;
       
       /* Load the old inode back in.  */
diff --git a/fs/ntfs.c b/fs/ntfs.c
index 22477c5..5d18159 100644
--- a/fs/ntfs.c
+++ b/fs/ntfs.c
@@ -864,7 +864,8 @@ fail:
 
 static grub_err_t
 grub_ntfs_dir (grub_device_t device, const char *path,
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ntfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -877,14 +878,11 @@ grub_ntfs_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
diff --git a/fs/reiserfs.c b/fs/reiserfs.c
index 8e91149..433e89b 100644
--- a/fs/reiserfs.c
+++ b/fs/reiserfs.c
@@ -1266,7 +1266,8 @@ grub_reiserfs_close (grub_file_t file)
 /* Call HOOK with each file under DIR.  */
 static grub_err_t
 grub_reiserfs_dir (grub_device_t device, const char *path,
-                   int (*hook) (const char *filename, int dir))
+                   int (*hook) (const char *filename, 
+				const struct grub_dirhook_info *info))
 {
   struct grub_reiserfs_data *data = 0;
   struct grub_fshelp_node root, *found;
@@ -1280,12 +1281,11 @@ grub_reiserfs_dir (grub_device_t device, const char *path,
                                 enum grub_fshelp_filetype filetype,
                                 grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-        return hook (filename, 1);
-      else
-        return hook (filename, 0);
+      return hook (filename, &info);
     }
 #ifndef GRUB_UTIL
   grub_dl_ref (my_mod);
diff --git a/fs/sfs.c b/fs/sfs.c
index d719e29..314a6fd 100644
--- a/fs/sfs.c
+++ b/fs/sfs.c
@@ -519,7 +519,8 @@ grub_sfs_read (grub_file_t file, char *buf, grub_size_t len)
 
 static grub_err_t
 grub_sfs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_sfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -532,14 +533,11 @@ grub_sfs_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
diff --git a/fs/udf.c b/fs/udf.c
index 072e44f..abe992e 100644
--- a/fs/udf.c
+++ b/fs/udf.c
@@ -768,7 +768,8 @@ grub_udf_iterate_dir (grub_fshelp_node_t dir,
 
 static grub_err_t
 grub_udf_dir (grub_device_t device, const char *path,
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_udf_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -782,14 +783,11 @@ grub_udf_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
   {
-    grub_free (node);
-
-    if (filetype == GRUB_FSHELP_DIR)
-      return hook (filename, 1);
-    else
-      return hook (filename, 0);
-
-    return 0;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
+      grub_free (node);
+      return hook (filename, &info);
   }
 
 #ifndef GRUB_UTIL
diff --git a/fs/ufs.c b/fs/ufs.c
index 1f333b0..e6eacd3 100644
--- a/fs/ufs.c
+++ b/fs/ufs.c
@@ -36,7 +36,10 @@
 #define GRUB_UFS_DIRBLKS	12
 #define GRUB_UFS_INDIRBLKS	3
 
-#define GRUB_UFS_ATTR_DIR	040000
+#define GRUB_UFS_ATTR_TYPE      0160000
+#define GRUB_UFS_ATTR_FILE	0100000
+#define GRUB_UFS_ATTR_DIR	0040000
+#define GRUB_UFS_ATTR_LNK       0120000
 
 #define GRUB_UFS_VOLNAME_LEN	32
 
@@ -71,16 +74,18 @@ struct grub_ufs_sblock
   
   /* The start of the cylinder group.  */
   grub_uint32_t cylg_offset;
-  
-  grub_uint8_t unused3[20];
+  grub_uint8_t unused3[4];
+
+  grub_uint32_t mtime;
+  grub_uint8_t unused4[12];
   
   /* The size of a block in bytes.  */
   grub_int32_t bsize;
-  grub_uint8_t unused4[48];
+  grub_uint8_t unused5[48];
   
   /* The size of filesystem blocks to disk blocks.  */
   grub_uint32_t log2_blksz;
-  grub_uint8_t unused5[80];
+  grub_uint8_t unused6[80];
   
   /* Inodes stored per cylinder group.  */
   grub_uint32_t ino_per_group;
@@ -92,8 +97,10 @@ struct grub_ufs_sblock
 
   /* Volume name for UFS2.  */
   grub_uint8_t volume_name[GRUB_UFS_VOLNAME_LEN];
+  grub_uint8_t unused8[232];
 
-  grub_uint8_t unused8[660];
+  grub_uint64_t mtime2;
+  grub_uint8_t unused9[420];
   
   /* Magic value to check if this is really a UFS filesystem.  */
   grub_uint32_t magic;
@@ -124,7 +131,7 @@ struct grub_ufs_inode
   grub_uint32_t gen;
   grub_uint32_t unused;
   grub_uint8_t pad[12];
-};
+} __attribute__ ((packed));
 
 /* UFS inode.  */
 struct grub_ufs2_inode
@@ -160,7 +167,7 @@ struct grub_ufs2_inode
   };
 
   grub_uint8_t unused[24];
-};
+} __attribute__ ((packed));
 
 /* Directory entry.  */
 struct grub_ufs_dirent
@@ -169,7 +176,7 @@ struct grub_ufs_dirent
   grub_uint16_t direntlen;
   grub_uint8_t filetype;
   grub_uint8_t namelen;
-};
+} __attribute__ ((packed));
 
 /* Information about a "mounted" ufs filesystem.  */
 struct grub_ufs_data
@@ -320,7 +327,7 @@ grub_ufs_read_file (struct grub_ufs_data *data,
 /* Read inode INO from the mounted filesystem described by DATA.  This
    inode is used by default now.  */
 static grub_err_t
-grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
+grub_ufs_read_inode (struct grub_ufs_data *data, int ino, char *inode)
 {
   struct grub_ufs_sblock *sblock = &data->sblock;
   
@@ -335,8 +342,12 @@ grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
   
   if (data->ufs_type == UFS1)
     {
-      struct grub_ufs_inode *inode = &data->inode;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -347,8 +358,12 @@ grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
     }
   else
     {
-      struct grub_ufs2_inode *inode = &data->inode2;
-      
+      if (!inode)
+	{
+	  inode = (char *) &data->inode2;
+	  data->ino = ino;
+	}
+
       grub_disk_read (data->disk,
 		      (((grub_le_to_cpu32 (sblock->inoblk_offs) + grpblk)
 			<< grub_le_to_cpu32 (data->sblock.log2_blksz)))
@@ -358,7 +373,6 @@ grub_ufs_read_inode (struct grub_ufs_data *data, int ino)
 		      (char *) inode);
     }
   
-  data->ino = ino;
   return grub_errno;
 }
 
@@ -390,7 +404,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
     ino = GRUB_UFS_INODE;
   
   /* Now load in the old inode.  */
-  if (grub_ufs_read_inode (data, ino))
+  if (grub_ufs_read_inode (data, ino, 0))
     return grub_errno;
   
   grub_ufs_find_file (data, symlink);
@@ -453,9 +467,10 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
 	if (!grub_strcmp (name, filename))
 	  {
 	    dirino = data->ino;
-	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino));
-	    
-	    if (dirent.filetype == GRUB_UFS_FILETYPE_LNK)
+	    grub_ufs_read_inode (data, grub_le_to_cpu32 (dirent.ino), 0);
+
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE)
+		== GRUB_UFS_ATTR_LNK)
 	      {
 		grub_ufs_lookup_symlink (data, dirino);
 		if (grub_errno)
@@ -475,7 +490,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
 		next++;
 	      }
 	    
-	    if (!(dirent.filetype & GRUB_UFS_FILETYPE_DIR))
+	    if ((INODE_MODE(data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
 	      return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
 	    
 	    continue;
@@ -544,7 +559,8 @@ grub_ufs_mount (grub_disk_t disk)
 
 static grub_err_t
 grub_ufs_dir (grub_device_t device, const char *path, 
-	       int (*hook) (const char *filename, int dir))
+	       int (*hook) (const char *filename, 
+			    const struct grub_dirhook_info *info))
 {
   struct grub_ufs_data *data;
   struct grub_ufs_sblock *sblock;
@@ -554,7 +570,7 @@ grub_ufs_dir (grub_device_t device, const char *path,
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, GRUB_UFS_INODE);
+  grub_ufs_read_inode (data, GRUB_UFS_INODE, 0);
   if (grub_errno)
     return grub_errno;
   
@@ -570,7 +586,7 @@ grub_ufs_dir (grub_device_t device, const char *path,
   if (grub_errno)
     goto fail;  
   
-  if (!(INODE_MODE (data) & GRUB_UFS_ATTR_DIR))
+  if ((INODE_MODE (data) & GRUB_UFS_ATTR_TYPE) != GRUB_UFS_ATTR_DIR)
     {
       grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory");
       goto fail;
@@ -586,13 +602,34 @@ grub_ufs_dir (grub_device_t device, const char *path,
       
       {
 	char filename[dirent.namelen + 1];
+	struct grub_dirhook_info info;
+	grub_memset (&info, 0, sizeof (info));
 	
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
 				dirent.namelen, filename) < 0)
 	  break;
 	
 	filename[dirent.namelen] = '\0';
-	if (hook (filename, dirent.filetype == GRUB_UFS_FILETYPE_DIR))
+	if (data->ufs_type == UFS1)
+	  {
+	    struct grub_ufs_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+	else
+	  {
+	    struct grub_ufs2_inode inode;
+	    grub_ufs_read_inode (data, dirent.ino, (char *) &inode);
+	    info.dir = ((grub_le_to_cpu16 (inode.mode) & GRUB_UFS_ATTR_TYPE)
+			== GRUB_UFS_ATTR_DIR);
+	    info.mtime = grub_le_to_cpu64 (inode.mtime);
+	    info.mtimeset = 1;
+	  }
+
+	if (hook (filename, &info))
 	  break;
       }
       
@@ -615,7 +652,7 @@ grub_ufs_open (struct grub_file *file, const char *name)
   if (!data)
     return grub_errno;
   
-  grub_ufs_read_inode (data, 2);
+  grub_ufs_read_inode (data, 2, 0);
   if (grub_errno)
     {
       grub_free (data);
@@ -688,6 +725,34 @@ grub_ufs_label (grub_device_t device, char **label)
   return grub_errno;
 }
 
+/* Get mtime.  */
+static grub_err_t 
+grub_ufs_mtime (grub_device_t device, grub_int32_t *tm)
+{
+  struct grub_ufs_data *data = 0;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ufs_mount (device->disk);
+  if (!data)
+    *tm = 0;
+  else if (data->ufs_type == UFS1)
+    *tm = grub_le_to_cpu32 (data->sblock.mtime);
+  else
+    *tm = grub_le_to_cpu64 (data->sblock.mtime2);
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+}
+
+
 \f
 static struct grub_fs grub_ufs_fs =
   {
@@ -697,6 +762,7 @@ static struct grub_fs grub_ufs_fs =
     .read = grub_ufs_read,
     .close = grub_ufs_close,
     .label = grub_ufs_label,
+    .mtime = grub_ufs_mtime,
     .next = 0
   };
 
diff --git a/fs/xfs.c b/fs/xfs.c
index 81a2771..a5c2d42 100644
--- a/fs/xfs.c
+++ b/fs/xfs.c
@@ -620,7 +620,8 @@ grub_xfs_mount (grub_disk_t disk)
 \f
 static grub_err_t
 grub_xfs_dir (grub_device_t device, const char *path, 
-	      int (*hook) (const char *filename, int dir))
+	      int (*hook) (const char *filename, 
+			   const struct grub_dirhook_info *info))
 {
   struct grub_xfs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -633,14 +634,11 @@ grub_xfs_dir (grub_device_t device, const char *path,
 				enum grub_fshelp_filetype filetype,
 				grub_fshelp_node_t node)
     {
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
+      info.dir = ((filetype & GRUB_FSHELP_TYPE_MASK) == GRUB_FSHELP_DIR);
       grub_free (node);
-      
-      if (filetype == GRUB_FSHELP_DIR)
-	return hook (filename, 1);
-      else 
-	return hook (filename, 0);
-      
-      return 0;
+      return hook (filename, &info);
     }
 
 #ifndef GRUB_UTIL
diff --git a/hook/datehook.c b/hook/datehook.c
index 9419d48..0b03328 100644
--- a/hook/datehook.c
+++ b/hook/datehook.c
@@ -22,7 +22,7 @@
 #include <grub/env.h>
 #include <grub/misc.h>
 #include <grub/normal.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 static char *grub_datetime_names[] =
 {
diff --git a/include/grub/datetime.h b/include/grub/datetime.h
new file mode 100644
index 0000000..f4bdae2
--- /dev/null
+++ b/include/grub/datetime.h
@@ -0,0 +1,48 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_DATETIME_HEADER
+#define KERNEL_DATETIME_HEADER	1
+
+#include <grub/types.h>
+#include <grub/err.h>
+
+struct grub_datetime
+{
+  grub_uint16_t year;
+  grub_uint8_t month;
+  grub_uint8_t day;
+  grub_uint8_t hour;
+  grub_uint8_t minute;
+  grub_uint8_t second;
+};
+
+/* Return date and time.  */
+grub_err_t grub_get_datetime (struct grub_datetime *datetime);
+
+/* Set date and time.  */
+grub_err_t grub_set_datetime (struct grub_datetime *datetime);
+
+int grub_get_weekday (struct grub_datetime *datetime);
+char *grub_get_weekday_name (struct grub_datetime *datetime);
+
+void grub_unixtime2datetime (grub_int32_t nix, 
+			     struct grub_datetime *datetime);
+
+
+#endif /* ! KERNEL_DATETIME_HEADER */
diff --git a/include/grub/fs.h b/include/grub/fs.h
index 46c7492..fa2c070 100644
--- a/include/grub/fs.h
+++ b/include/grub/fs.h
@@ -27,6 +27,14 @@
 /* Forward declaration is required, because of mutual reference.  */
 struct grub_file;
 
+struct grub_dirhook_info
+{
+  int dir:1;
+  int mtimeset:1;
+  int case_insensitive:1;
+  grub_int32_t mtime;
+};
+
 /* Filesystem descriptor.  */
 struct grub_fs
 {
@@ -35,7 +43,8 @@ struct grub_fs
 
   /* Call HOOK with each file under DIR.  */
   grub_err_t (*dir) (grub_device_t device, const char *path,
-		     int (*hook) (const char *filename, int dir));
+		     int (*hook) (const char *filename, 
+				  const struct grub_dirhook_info *info));
   
   /* Open a file named NAME and initialize FILE.  */
   grub_err_t (*open) (struct grub_file *file, const char *name);
@@ -56,6 +65,9 @@ struct grub_fs
      caller.  */
   grub_err_t (*uuid) (grub_device_t device, char **uuid);
 
+  /* Get writing time of filesystem. */
+  grub_err_t (*mtime) (grub_device_t device, grub_int32_t *timebuf);
+
   /* The next filesystem.  */
   struct grub_fs *next;
 };
diff --git a/include/grub/fshelp.h b/include/grub/fshelp.h
index 7092cac..42d8da5 100644
--- a/include/grub/fshelp.h
+++ b/include/grub/fshelp.h
@@ -27,6 +27,8 @@
 typedef struct grub_fshelp_node *grub_fshelp_node_t;
 
 #define GRUB_FSHELP_CASE_INSENSITIVE	0x100
+#define GRUB_FSHELP_TYPE_MASK	0xff
+#define GRUB_FSHELP_FLAGS_MASK	0x100
 
 enum grub_fshelp_filetype
   {
diff --git a/include/grub/lib/datetime.h b/include/grub/lib/datetime.h
index 7b140cc..e69de29 100644
--- a/include/grub/lib/datetime.h
+++ b/include/grub/lib/datetime.h
@@ -1,44 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef KERNEL_DATETIME_HEADER
-#define KERNEL_DATETIME_HEADER	1
-
-#include <grub/types.h>
-#include <grub/err.h>
-
-struct grub_datetime
-{
-  grub_uint16_t year;
-  grub_uint8_t month;
-  grub_uint8_t day;
-  grub_uint8_t hour;
-  grub_uint8_t minute;
-  grub_uint8_t second;
-};
-
-/* Return date and time.  */
-grub_err_t grub_get_datetime (struct grub_datetime *datetime);
-
-/* Set date and time.  */
-grub_err_t grub_set_datetime (struct grub_datetime *datetime);
-
-int grub_get_weekday (struct grub_datetime *datetime);
-char *grub_get_weekday_name (struct grub_datetime *datetime);
-
-#endif /* ! KERNEL_DATETIME_HEADER */
diff --git a/kern/fs.c b/kern/fs.c
index 4e21de2..e2e4300 100644
--- a/kern/fs.c
+++ b/kern/fs.c
@@ -65,10 +65,11 @@ grub_fs_t
 grub_fs_probe (grub_device_t device)
 {
   grub_fs_t p;
-  auto int dummy_func (const char *filename, int dir);
+  auto int dummy_func (const char *filename, 
+		       const struct grub_dirhook_info *info);
 
   int dummy_func (const char *filename __attribute__ ((unused)),
-		  int dir __attribute__ ((unused)))
+		  const struct grub_dirhook_info *info  __attribute__ ((unused)))
     {
       return 1;
     }
diff --git a/kern/rescue.c b/kern/rescue.c
index e333ab5..1763d57 100644
--- a/kern/rescue.c
+++ b/kern/rescue.c
@@ -176,9 +176,10 @@ grub_rescue_print_devices (const char *name)
 }
 
 static int
-grub_rescue_print_files (const char *filename, int dir)
+grub_rescue_print_files (const char *filename, 
+			  const struct grub_dirhook_info *info)
 {
-  grub_printf ("%s%s ", filename, dir ? "/" : "");
+  grub_printf ("%s%s ", filename, info->dir ? "/" : "");
   
   return 0;
 }
diff --git a/lib/datetime.c b/lib/datetime.c
index 7215a6a..e69de29 100644
--- a/lib/datetime.c
+++ b/lib/datetime.c
@@ -1,49 +0,0 @@
-/* datetime.c - Module for common datetime function.  */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2008  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <grub/lib/datetime.h>
-
-static char *grub_weekday_names[] =
-{
-  "Sunday",
-  "Monday",
-  "Tuesday",
-  "Wednesday",
-  "Thursday",
-  "Friday",
-  "Saturday",
-};
-
-int
-grub_get_weekday (struct grub_datetime *datetime)
-{
-  int a, y, m;
-
-  a = (14 - datetime->month) / 12;
-  y = datetime->year - a;
-  m = datetime->month + 12 * a - 2;
-
-  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
-}
-
-char *
-grub_get_weekday_name (struct grub_datetime *datetime)
-{
-  return grub_weekday_names[grub_get_weekday (datetime)];
-}
diff --git a/lib/efi/datetime.c b/lib/efi/datetime.c
index 9fa72fd..0a91c34 100644
--- a/lib/efi/datetime.c
+++ b/lib/efi/datetime.c
@@ -21,7 +21,7 @@
 #include <grub/symbol.h>
 #include <grub/efi/api.h>
 #include <grub/efi/efi.h>
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 
 grub_err_t
 grub_get_datetime (struct grub_datetime *datetime)
diff --git a/lib/i386/datetime.c b/lib/i386/datetime.c
index 1e59746..63858ed 100644
--- a/lib/i386/datetime.c
+++ b/lib/i386/datetime.c
@@ -17,7 +17,7 @@
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <grub/lib/datetime.h>
+#include <grub/datetime.h>
 #include <grub/i386/cmos.h>
 
 grub_err_t
diff --git a/normal/completion.c b/normal/completion.c
index fb38f28..c591660 100644
--- a/normal/completion.c
+++ b/normal/completion.c
@@ -123,9 +123,9 @@ iterate_partition (grub_disk_t disk, const grub_partition_t p)
 }
 
 static int
-iterate_dir (const char *filename, int dir)
+iterate_dir (const char *filename, const struct grub_dirhook_info *info)
 {
-  if (! dir)
+  if (! info->dir)
     {
       const char *prefix;
       if (cmdline_state == GRUB_PARSER_STATE_DQUOTE)
diff --git a/normal/datetime.c b/normal/datetime.c
new file mode 100644
index 0000000..272b716
--- /dev/null
+++ b/normal/datetime.c
@@ -0,0 +1,100 @@
+/* datetime.c - Module for common datetime function.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/datetime.h>
+
+static char *grub_weekday_names[] =
+{
+  "Sunday",
+  "Monday",
+  "Tuesday",
+  "Wednesday",
+  "Thursday",
+  "Friday",
+  "Saturday",
+};
+
+int
+grub_get_weekday (struct grub_datetime *datetime)
+{
+  int a, y, m;
+
+  a = (14 - datetime->month) / 12;
+  y = datetime->year - a;
+  m = datetime->month + 12 * a - 2;
+
+  return (datetime->day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
+}
+
+char *
+grub_get_weekday_name (struct grub_datetime *datetime)
+{
+  return grub_weekday_names[grub_get_weekday (datetime)];
+}
+
+#define SECPERMIN 60
+#define SECPERHOUR (60*SECPERMIN)
+#define SECPERDAY (24*SECPERHOUR)
+#define SECPERYEAR (365*SECPERDAY)
+#define SECPER4YEARS (4*SECPERYEAR+SECPERDAY)
+
+
+void
+grub_unixtime2datetime (grub_int32_t nix, struct grub_datetime *datetime)
+{
+  int i;
+  int div;
+  grub_uint8_t months[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 
+  /* In the period of validity of unixtime all years divisible by 4 
+     are bissextile*/
+  /* Convenience: let's have 3 consecutive non-bissextile years 
+     at the begining of the epoch. So count from 1973 instead of 1970 */
+  nix -= 3*SECPERYEAR + SECPERDAY;
+  /* Transform C divisions and modulos to mathematical ones */
+  div = nix / SECPER4YEARS;
+  if (nix < 0)
+    div--;
+  datetime->year = 1973 + 4 * div;
+  nix -= div * SECPER4YEARS;
+
+  /* On 31st december of bissextile years 365 days from the begining 
+     of the year elapsed but year isn't finished yet*/
+  if (nix / SECPERYEAR == 4)
+    {
+      datetime->year += 3;
+      nix -= 3*SECPERYEAR;
+    }
+  else
+    {
+      datetime->year += nix / SECPERYEAR;
+      nix %= SECPERYEAR;
+    }
+  for (i = 0; i < 12 
+	 && nix >= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+				    ? 29 : months[i]))*SECPERDAY; i++)
+    nix -= ((grub_int32_t) (i==1 && datetime->year % 4 == 0 
+			    ? 29 : months[i]))*SECPERDAY;
+  datetime->month = i + 1; 
+  datetime->day = 1 + (nix / SECPERDAY);
+  nix %= SECPERDAY;
+  datetime->hour = (nix / SECPERHOUR);  
+  nix %= SECPERHOUR;
+  datetime->minute = nix / SECPERMIN;
+  datetime->second = nix % SECPERMIN;
+}
diff --git a/normal/misc.c b/normal/misc.c
index e47ff87..bf677db 100644
--- a/normal/misc.c
+++ b/normal/misc.c
@@ -23,6 +23,7 @@
 #include <grub/err.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
+#include <grub/datetime.h>
 
 /* Print the information on the device NAME.  */
 grub_err_t
@@ -63,6 +64,23 @@ grub_normal_print_device_info (const char *name)
 		}
 	      grub_errno = GRUB_ERR_NONE;
 	    }
+	  if (fs->mtime)
+	    {
+	      grub_int32_t tm;
+	      struct grub_datetime datetime;
+	      (fs->mtime) (dev, &tm);
+	      if (grub_errno == GRUB_ERR_NONE)
+		{
+		  grub_unixtime2datetime (tm, &datetime);
+		  grub_printf (", Last modification time %d-%02d-%02d "
+			       "%02d:%02d:%02d %s",
+			       datetime.year, datetime.month, datetime.day,
+			       datetime.hour, datetime.minute, datetime.second,
+			       grub_get_weekday_name (&datetime));
+
+		}
+	      grub_errno = GRUB_ERR_NONE;
+	    }
 	  if (fs->uuid)
 	    {
 	      char *uuid;
diff --git a/util/hostfs.c b/util/hostfs.c
index d68c36f..f82d39b 100644
--- a/util/hostfs.c
+++ b/util/hostfs.c
@@ -16,7 +16,7 @@
  *  You should have received a copy of the GNU General Public License
  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  */
-
+#define _BSD_SOURCE
 #include <grub/fs.h>
 #include <grub/file.h>
 #include <grub/disk.h>
@@ -57,7 +57,8 @@ is_dir (const char *path, const char *name)
 
 static grub_err_t
 grub_hostfs_dir (grub_device_t device, const char *path, 
-		 int (*hook) (const char *filename, int dir))
+		 int (*hook) (const char *filename, 
+			      const struct grub_dirhook_info *info))
 {
   DIR *dir;
 
@@ -73,16 +74,20 @@ grub_hostfs_dir (grub_device_t device, const char *path,
   while (1)
     {
       struct dirent *de;
+      struct grub_dirhook_info info;
+      grub_memset (&info, 0, sizeof (info));
 
       de = readdir (dir);
       if (! de)
 	break;
 
 #ifdef DT_DIR
-      hook (de->d_name, de->d_type == DT_DIR);
+      info.dir = (de->d_type == DT_DIR);
 #else
-      hook (de->d_name, is_dir (path, de->d_name));
+      info.dir = !!is_dir (path, de->d_name);
 #endif
+      hook (de->d_name, &info);
+
     }
 
   closedir (dir);

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-13 19:10 ` Robert Millan
  2009-03-15  0:34   ` phcoder
@ 2009-03-15 11:16   ` phcoder
  1 sibling, 0 replies; 12+ messages in thread
From: phcoder @ 2009-03-15 11:16 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1273 bytes --]

UFS part (not related to mtime)
2009-03-15  Vladimir Serbinenko  <phcoder@gmail.com>

         UFS improvements

         * fs/ufs.c (GRUB_UFS_BSD_DIRENT): new definition
         (struct grub_ufs_dirent): added fields for non-BSD dirents
         (grub_ufs_get_file_block): fixed double indirect handling
         (grub_ufs_find_file): support for non-BSD dirents
         (grub_ufs_dir): support for non-BSD dirents


Robert Millan wrote:
> On Sun, Mar 01, 2009 at 05:25:10PM +0100, phcoder wrote:
>> Hello all. It seems that gcc has trouble with -m32 when structure is  
>> passed as argument. So I replaced that part by a pointer. Also I made  
>> some improvements to ufs code to support solaris branch of ufs. I tested  
>> it also with freebsd and netbsd's branch and it works fine on it too.
>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a  
>> patch with all 3 features. If it's really necessary I can split them but  
>> it requires a lot of unnecessary work
> 
> Please do.  It is definitely confusing to review patches that merge
> unrelated things.
> 
> Also, please don't include the changelog entry in your patch, since those
> break too easily.  Just paste it at the top of your mail.
> 


-- 

Regards
Vladimir 'phcoder' Serbinenko

[-- Attachment #2: ufs.diff --]
[-- Type: text/x-diff, Size: 4021 bytes --]

diff --git a/fs/ufs.c b/fs/ufs.c
index e6eacd3..9a3cd69 100644
--- a/fs/ufs.c
+++ b/fs/ufs.c
@@ -54,6 +54,8 @@
                            grub_le_to_cpu##bits1 (data->inode.field) : \
                            grub_le_to_cpu##bits2 (data->inode2.field))
 #define INODE_SIZE(data) INODE_ENDIAN (data,size,32,64)
+#define INODE_NBLOCKS(data) INODE_ENDIAN (data,nblocks,32,64)
+
 #define INODE_MODE(data) INODE_ENDIAN (data,mode,16,16)
 #define INODE_BLKSZ(data) (data->ufs_type == UFS1 ? 4 : 8)
 #define INODE_DIRBLOCKS(data,blk) INODE_ENDIAN \
@@ -174,8 +176,15 @@ struct grub_ufs_dirent
 {
   grub_uint32_t ino;
   grub_uint16_t direntlen;
-  grub_uint8_t filetype;
-  grub_uint8_t namelen;
+  union
+  {
+    grub_uint16_t namelen;
+    struct
+    {
+      grub_uint8_t filetype_bsd;
+      grub_uint8_t namelen_bsd;      
+    };
+  };
 } __attribute__ ((packed));
 
 /* Information about a "mounted" ufs filesystem.  */
@@ -234,22 +243,23 @@ grub_ufs_get_file_block (struct grub_ufs_data *data, unsigned int blk)
   blk -= indirsz;
   
   /* Double indirect block.  */
-  if (blk < UFS_BLKSZ (sblock) / indirsz)
+  if (blk < indirsz * indirsz)
     {
       grub_uint32_t indir[UFS_BLKSZ (sblock) >> 2];
       
       grub_disk_read (data->disk, INODE_INDIRBLOCKS (data, 1) << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       grub_disk_read (data->disk,
-      		      (data->ufs_type == UFS1) ?
-		      indir[blk / indirsz] : indir [(blk / indirsz) << 1],
+      		      ((data->ufs_type == UFS1) ?
+		      indir[blk / indirsz] : indir [(blk / indirsz) << 1]) 
+		      << log2_blksz,
 		      0, sizeof (indir), (char *) indir);
       
       return (data->ufs_type == UFS1) ?
 	     indir[blk % indirsz] : indir[(blk % indirsz) << 1];
     }
 
-
+  
   grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 	      "ufs does not support triple indirect blocks");
   return 0;
@@ -386,9 +396,8 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
   
   if (++data->linknest > GRUB_UFS_MAX_SYMLNK_CNT)
     return grub_error (GRUB_ERR_SYMLINK_LOOP, "too deep nesting of symlinks");
-  
-  if (INODE_SIZE (data) < (GRUB_UFS_DIRBLKS + GRUB_UFS_INDIRBLKS
-			  * INODE_BLKSZ (data)))
+
+  if (INODE_NBLOCKS (data) == 0)
     grub_strcpy (symlink, (char *) INODE (data, symlink));
   else
     {
@@ -447,6 +456,7 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
   do
     {
       struct grub_ufs_dirent dirent;
+      int namelen;
       
       if (grub_strlen (name) == 0)
 	return GRUB_ERR_NONE;
@@ -454,15 +464,18 @@ grub_ufs_find_file (struct grub_ufs_data *data, const char *path)
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	return grub_errno;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
 
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  return grub_errno;
 	
-	filename[dirent.namelen] = '\0';
+	filename[namelen] = '\0';
 	
 	if (!grub_strcmp (name, filename))
 	  {
@@ -595,21 +608,25 @@ grub_ufs_dir (grub_device_t device, const char *path,
   while (pos < INODE_SIZE (data))
     {
       struct grub_ufs_dirent dirent;
+      int namelen;
       
       if (grub_ufs_read_file (data, 0, pos, sizeof (dirent),
 			      (char *) &dirent) < 0)
 	break;
+
+      namelen = (data->ufs_type == UFS2)
+	? dirent.namelen_bsd : grub_le_to_cpu16 (dirent.namelen);
       
       {
-	char filename[dirent.namelen + 1];
+	char filename[namelen + 1];
 	struct grub_dirhook_info info;
 	grub_memset (&info, 0, sizeof (info));
 	
 	if (grub_ufs_read_file (data, 0, pos + sizeof (dirent),
-				dirent.namelen, filename) < 0)
+				namelen, filename) < 0)
 	  break;
 	
-	filename[dirent.namelen] = '\0';
+	filename[namelen] = '\0';
 	if (data->ufs_type == UFS1)
 	  {
 	    struct grub_ufs_inode inode;

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-03-15  0:34   ` phcoder
@ 2009-04-04  9:21     ` phcoder
  2009-04-05 14:38       ` Yoshinori K. Okuji
  0 siblings, 1 reply; 12+ messages in thread
From: phcoder @ 2009-04-04  9:21 UTC (permalink / raw)
  To: The development of GRUB 2

Can someone review this patch?
phcoder wrote:
> mtime part
> 2009-03-15  Vladimir Serbinenko  <phcoder@gmail.com>
> 
>     Support for mtime and further expandability of dir command
> 
>     * include/grub/lib/datetime.h: moved to ...
>     * include/grub/datetime.h: ... moved here and added
>     declaration of grub_unixtime2datetime. All users updated
>     * include/grub/fs.h: new syntax for dir and mtime functionin
>     struct grub_fs
>     * include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
>     and GRUB_FSHELP_FLAGS_MASK
>     * commands/ls.c (grub_ls_list_files): Write mtime in long format
>     * fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
>     (grub_ext2_mtime): new function
>     * fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply mtime
>     (grub_hfsplus_mtime): new function
>     * fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
>     (GRUB_UFS_ATTR_FILE): likewise
>     (GRUB_UFS_ATTR_LNK): likewise
>     (struct grub_ufs_sblock): new fields mtime
>     (grub_ufs_read_inode): new parameter to read inode to a separate buffer
>     all users updated
>     (grub_ufs_dir): mtime support
>     (grub_ufs_mtime): new function
>     * fs/affs.c (grub_affs_dir): use new dir syntax
>     * fs/afs.c (grub_afs_dir): likewise
>     * fs/cpio.c (grub_cpio_dir): likewise
>     * fs/fat.c (grub_fat_find_dir): likewise
>     * fs/hfs.c (grub_hfs_dir): likewise
>     * fs/iso9660.c (grub_iso9660_dir): likewise
>     * fs/jfs.c (grub_jfs_dir): likewise
>     * fs/minix.c (grub_minix_dir): likewise
>     * fs/ntfs.c (grub_ntfs_dir): likewise
>     * fs/reiserfs.c (grub_reiserfs_dir): likewise
>     * fs/sfs.c (grub_sfs_dir): likewise
>     * fs/xfs.c (grub_xfs_dir): likewise
>     * util/hostfs.c (grub_hostfs_dir): likewise
>     * lib/datetime.c: moved to ...
>     * normal/datetime.c: ... moved here
>     (grub_unixtime2datetime): new function
>     * kern/rescue.c (grub_rescue_print_files): use new dir syntax
>     * normal/completition.c (iterate_dir): use new dir syntax
>     * normal/misc.c (grub_normal_print_device_info): tell the
>     last modification time of a volume
>     * kern/fs.c (grub_fs_probe): updated dummy function to use new syntax
>     * conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu
>     and normal.mod. Removed lib/datetime.c from datetime.mod
>     * conf/i386-efi.rmk: likewise
>     * conf/i386-ieee1275.rmk: likewise   
>     * conf/i386-pc.rmk: likewise
>     * conf/powerpc-ieee1275.rmk: likewise
>     * conf/sparc64-ieee1275.rmk: likewise   
>     * conf/x86_64-efi.rmk: likewise   
>     
> 
> Robert Millan wrote:
>> On Sun, Mar 01, 2009 at 05:25:10PM +0100, phcoder wrote:
>>> Hello all. It seems that gcc has trouble with -m32 when structure is  
>>> passed as argument. So I replaced that part by a pointer. Also I 
>>> made  some improvements to ufs code to support solaris branch of ufs. 
>>> I tested  it also with freebsd and netbsd's branch and it works fine 
>>> on it too.
>>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a  
>>> patch with all 3 features. If it's really necessary I can split them 
>>> but  it requires a lot of unnecessary work
>>
>> Please do.  It is definitely confusing to review patches that merge
>> unrelated things.
>>
>> Also, please don't include the changelog entry in your patch, since those
>> break too easily.  Just paste it at the top of your mail.
>>
> 
> 


-- 

Regards
Vladimir 'phcoder' Serbinenko



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FAT, UFS and mtime
  2009-04-04  9:21     ` phcoder
@ 2009-04-05 14:38       ` Yoshinori K. Okuji
  0 siblings, 0 replies; 12+ messages in thread
From: Yoshinori K. Okuji @ 2009-04-05 14:38 UTC (permalink / raw)
  To: The development of GRUB 2

On Saturday 04 April 2009 18:21:40 phcoder wrote:
> Can someone review this patch?

Looks good to me.

Thanks,
Okuji

> phcoder wrote:
> > mtime part
> > 2009-03-15  Vladimir Serbinenko  <phcoder@gmail.com>
> >
> >     Support for mtime and further expandability of dir command
> >
> >     * include/grub/lib/datetime.h: moved to ...
> >     * include/grub/datetime.h: ... moved here and added
> >     declaration of grub_unixtime2datetime. All users updated
> >     * include/grub/fs.h: new syntax for dir and mtime functionin
> >     struct grub_fs
> >     * include/grub/fshelp.h: new declarations of GRUB_FSHELP_TYPE_MASK
> >     and GRUB_FSHELP_FLAGS_MASK
> >     * commands/ls.c (grub_ls_list_files): Write mtime in long format
> >     * fs/ext2.c (grub_ext2_dir): use new dir syntax and supply mtime
> >     (grub_ext2_mtime): new function
> >     * fs/hfsplus.c (grub_hfsplus_dir): use new dir syntax and supply
> > mtime (grub_hfsplus_mtime): new function
> >     * fs/ufs.c (GRUB_UFS_ATTR_TYPE): new definition
> >     (GRUB_UFS_ATTR_FILE): likewise
> >     (GRUB_UFS_ATTR_LNK): likewise
> >     (struct grub_ufs_sblock): new fields mtime
> >     (grub_ufs_read_inode): new parameter to read inode to a separate
> > buffer all users updated
> >     (grub_ufs_dir): mtime support
> >     (grub_ufs_mtime): new function
> >     * fs/affs.c (grub_affs_dir): use new dir syntax
> >     * fs/afs.c (grub_afs_dir): likewise
> >     * fs/cpio.c (grub_cpio_dir): likewise
> >     * fs/fat.c (grub_fat_find_dir): likewise
> >     * fs/hfs.c (grub_hfs_dir): likewise
> >     * fs/iso9660.c (grub_iso9660_dir): likewise
> >     * fs/jfs.c (grub_jfs_dir): likewise
> >     * fs/minix.c (grub_minix_dir): likewise
> >     * fs/ntfs.c (grub_ntfs_dir): likewise
> >     * fs/reiserfs.c (grub_reiserfs_dir): likewise
> >     * fs/sfs.c (grub_sfs_dir): likewise
> >     * fs/xfs.c (grub_xfs_dir): likewise
> >     * util/hostfs.c (grub_hostfs_dir): likewise
> >     * lib/datetime.c: moved to ...
> >     * normal/datetime.c: ... moved here
> >     (grub_unixtime2datetime): new function
> >     * kern/rescue.c (grub_rescue_print_files): use new dir syntax
> >     * normal/completition.c (iterate_dir): use new dir syntax
> >     * normal/misc.c (grub_normal_print_device_info): tell the
> >     last modification time of a volume
> >     * kern/fs.c (grub_fs_probe): updated dummy function to use new syntax
> >     * conf/i386-coreboot.rmk: added normal/datetime.c to grub-emu
> >     and normal.mod. Removed lib/datetime.c from datetime.mod
> >     * conf/i386-efi.rmk: likewise
> >     * conf/i386-ieee1275.rmk: likewise
> >     * conf/i386-pc.rmk: likewise
> >     * conf/powerpc-ieee1275.rmk: likewise
> >     * conf/sparc64-ieee1275.rmk: likewise
> >     * conf/x86_64-efi.rmk: likewise
> >
> > Robert Millan wrote:
> >> On Sun, Mar 01, 2009 at 05:25:10PM +0100, phcoder wrote:
> >>> Hello all. It seems that gcc has trouble with -m32 when structure is
> >>> passed as argument. So I replaced that part by a pointer. Also I
> >>> made  some improvements to ufs code to support solaris branch of ufs.
> >>> I tested  it also with freebsd and netbsd's branch and it works fine
> >>> on it too.
> >>> As my 3 FS patches: mtime, FAT and UFS are interdependent I submit a
> >>> patch with all 3 features. If it's really necessary I can split them
> >>> but  it requires a lot of unnecessary work
> >>
> >> Please do.  It is definitely confusing to review patches that merge
> >> unrelated things.
> >>
> >> Also, please don't include the changelog entry in your patch, since
> >> those break too easily.  Just paste it at the top of your mail.





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2009-04-05 14:39 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-03-01 16:25 [PATCH] FAT, UFS and mtime phcoder
2009-03-01 19:13 ` Bean
2009-03-01 21:17   ` phcoder
2009-03-02  3:58     ` Bean
2009-03-02  4:39       ` Pavel Roskin
2009-03-11 21:32 ` phcoder
2009-03-11 22:16   ` phcoder
2009-03-13 19:10 ` Robert Millan
2009-03-15  0:34   ` phcoder
2009-04-04  9:21     ` phcoder
2009-04-05 14:38       ` Yoshinori K. Okuji
2009-03-15 11:16   ` phcoder

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.