All of lore.kernel.org
 help / color / mirror / Atom feed
From: phcoder <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: [PATCH] mtime support
Date: Thu, 12 Feb 2009 18:13:30 +0100	[thread overview]
Message-ID: <499458BA.4010700@gmail.com> (raw)
In-Reply-To: <49943AE4.5040008@gmail.com>

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

Made corrections to issues pointed by Vesa Jääskeläinen
Regards
Vladimir 'phcoder' Serbinenko

phcoder wrote:
> Hello. Here is the patch to support mtime. This is a prerequisite for 
> -nt test which can be very useful for e.g. finding last compiled kernel
> Also in the same time it makes the dir call easily extendable
> 
> Regards
> Vladimir 'phcoder' Serbinenko
> 


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

Index: conf/common.rmk
===================================================================
Index: conf/i386-coreboot.rmk
===================================================================
--- conf/i386-coreboot.rmk	(revision 1989)
+++ conf/i386-coreboot.rmk	(working copy)
@@ -75,7 +75,7 @@
 	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/completion.c normal/datetime.c normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
@@ -121,7 +121,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
Index: conf/i386-efi.rmk
===================================================================
--- conf/i386-efi.rmk	(revision 1989)
+++ conf/i386-efi.rmk	(working copy)
@@ -52,7 +52,8 @@
 	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/misc.c normal/script.c					\
 	normal/color.c							\
@@ -118,9 +119,9 @@
 # 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/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)
@@ -175,7 +176,7 @@
 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 1989)
+++ conf/i386-ieee1275.rmk	(working copy)
@@ -74,7 +74,7 @@
 	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/completion.c normal/datetime.c normal/main.c		\
 	normal/menu.c normal/menu_entry.c normal/menu_viewer.c		\
 	normal/misc.c normal/script.c					\
 	normal/color.c							\
@@ -111,7 +111,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
@@ -190,7 +192,7 @@
 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 1989)
+++ conf/i386-pc.rmk	(working copy)
@@ -128,7 +128,8 @@
 	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/misc.c normal/script.c					\
 	partmap/amiga.c	partmap/apple.c partmap/pc.c partmap/sun.c	\
@@ -208,7 +228,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
@@ -344,7 +368,7 @@
 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 1989)
+++ conf/powerpc-ieee1275.rmk	(working copy)
@@ -56,7 +56,7 @@
 	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_entry.c normal/menu_viewer.c normal/misc.c 		\
 	normal/script.c							\
@@ -131,7 +131,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
Index: conf/sparc64-ieee1275.rmk
===================================================================
--- conf/sparc64-ieee1275.rmk	(revision 1989)
+++ conf/sparc64-ieee1275.rmk	(working copy)
@@ -56,7 +56,8 @@
 #	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_viewer.c normal/misc.c				\
@@ -164,7 +165,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
Index: conf/x86_64-efi.rmk
===================================================================
--- conf/x86_64-efi.rmk	(revision 1989)
+++ conf/x86_64-efi.rmk	(working copy)
@@ -54,7 +54,8 @@
 	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/misc.c normal/script.c					\
 	normal/color.c							\
@@ -120,7 +121,7 @@
 # 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/color.c							\
 	normal/menu_viewer.c normal/menu_entry.c			\
@@ -177,7 +178,7 @@
 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 1989)
+++ kern/fs.c	(working copy)
@@ -65,10 +65,10 @@
 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, struct grub_dirhook_info info);
 
   int dummy_func (const char *filename __attribute__ ((unused)),
-		  int dir __attribute__ ((unused)))
+		  struct grub_dirhook_info info  __attribute__ ((unused)))
     {
       return 1;
     }
Index: kern/rescue.c
===================================================================
--- kern/rescue.c	(revision 1989)
+++ kern/rescue.c	(working copy)
@@ -176,9 +176,9 @@
 }
 
 static int
-grub_rescue_print_files (const char *filename, int dir)
+grub_rescue_print_files (const char *filename, 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 1989)
+++ 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 1989)
+++ 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/i386/datetime.c
===================================================================
--- lib/i386/datetime.c	(revision 1989)
+++ lib/i386/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>
 #include <grub/i386/cmos.h>
 
 grub_err_t
Index: lib/datetime.c
===================================================================
--- lib/datetime.c	(revision 1989)
+++ 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 1989)
+++ fs/xfs.c	(working copy)
@@ -620,7 +620,7 @@
 \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, struct grub_dirhook_info info))
 {
   struct grub_xfs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -633,14 +633,11 @@
 				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 1989)
+++ fs/afs.c	(working copy)
@@ -562,7 +562,7 @@
 
 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, struct grub_dirhook_info info))
 {
   struct grub_afs_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -575,14 +575,11 @@
 				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 1989)
+++ fs/ntfs.c	(working copy)
@@ -864,7 +864,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_ntfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -877,14 +878,11 @@
 				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 1989)
+++ 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 @@
   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_free (filename);
       grub_free (unibuf);
-      grub_free (dirname);
       return 0;
     }
       
@@ -533,15 +503,8 @@
       /* 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_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,121 @@
 
       /* 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, 
+				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);
+
+    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, 
+			   struct grub_dirhook_info info))
 {
   struct grub_fat_data *data = 0;
   grub_disk_t disk = device->disk;
@@ -773,8 +797,17 @@
 {
   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 +823,10 @@
       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 1989)
+++ fs/udf.c	(working copy)
@@ -768,7 +768,7 @@
 
 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, struct grub_dirhook_info info))
 {
   struct grub_udf_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -782,14 +782,11 @@
 				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 1989)
+++ fs/iso9660.c	(working copy)
@@ -666,7 +666,8 @@
 \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, 
+			       struct grub_dirhook_info info))
 {
   struct grub_iso9660_data *data = 0;
   struct grub_fshelp_node rootnode;
@@ -680,14 +681,11 @@
 				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 1989)
+++ fs/affs.c	(working copy)
@@ -456,7 +456,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_affs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -469,14 +470,11 @@
 				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 1989)
+++ fs/hfs.c	(working copy)
@@ -721,7 +721,8 @@
 \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,
+			       struct grub_dirhook_info info))
 {
   int inode;
 
@@ -732,13 +733,17 @@
       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 1989)
+++ fs/reiserfs.c	(working copy)
@@ -1266,7 +1266,8 @@
 /* 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, 
+				struct grub_dirhook_info info))
 {
   struct grub_reiserfs_data *data = 0;
   struct grub_fshelp_node root, *found;
@@ -1280,12 +1281,11 @@
                                 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 1989)
+++ fs/jfs.c	(working copy)
@@ -728,7 +728,7 @@
 
 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, struct grub_dirhook_info info))
 {
   struct grub_jfs_data *data = 0;
   struct grub_jfs_diropen *diro = 0;
@@ -752,14 +752,15 @@
   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 1989)
+++ fs/ext2.c	(working copy)
@@ -662,11 +662,12 @@
 	  fdiro = grub_malloc (sizeof (struct grub_fshelp_node));
 	  if (! fdiro)
 	    return 0;
-	  
+
 	  fdiro->data = diro->data;
 	  fdiro->ino = grub_le_to_cpu32 (dirent.inode);
 	  
 	  filename[dirent.namelen] = '\0';
+	  
 
 	  if (dirent.filetype != FILETYPE_UNKNOWN)
 	    {
@@ -682,9 +683,10 @@
 	  else
 	    {
 	      /* The filetype can not be read from the dirent, read
-		 the inode to get more information.  */
+		 the inode to get more information.  */	      
+	      
 	      grub_ext2_read_inode (diro->data,
-                                    grub_le_to_cpu32 (dirent.inode),
+				    grub_le_to_cpu32 (dirent.inode),
 				    &fdiro->inode);
 	      if (grub_errno)
 		{
@@ -788,7 +790,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_ext2_data *data = 0;;
   struct grub_fshelp_node *fdiro = 0;
@@ -801,14 +804,24 @@
 				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 @@
   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 @@
     .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 1989)
+++ fs/minix.c	(working copy)
@@ -461,7 +461,8 @@
 \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, 
+			       struct grub_dirhook_info info))
 {
   struct grub_minix_data *data = 0;
   struct grub_minix_sblock *sblock;
@@ -492,6 +493,9 @@
       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 @@
       /* 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 1989)
+++ fs/hfsplus.c	(working copy)
@@ -885,7 +885,8 @@
 
 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, 
+			       struct grub_dirhook_info info))
 {
   struct grub_hfsplus_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -898,14 +899,11 @@
 				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/cpio.c
===================================================================
--- fs/cpio.c	(revision 1989)
+++ fs/cpio.c	(working copy)
@@ -183,7 +183,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_cpio_data *data;
   grub_uint32_t ofs;
@@ -227,7 +228,11 @@
 
 	  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 1989)
+++ fs/sfs.c	(working copy)
@@ -527,7 +527,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_sfs_data *data = 0;
   struct grub_fshelp_node *fdiro = 0;
@@ -540,14 +541,11 @@
 				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 1989)
+++ fs/ufs.c	(working copy)
@@ -544,7 +544,8 @@
 
 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, 
+			    struct grub_dirhook_info info))
 {
   struct grub_ufs_data *data;
   struct grub_ufs_sblock *sblock;
@@ -586,13 +587,16 @@
       
       {
 	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))
+	info.dir = (dirent.filetype == GRUB_UFS_FILETYPE_DIR);
+	if (hook (filename, info))
 	  break;
       }
       
Index: include/grub/fs.h
===================================================================
--- include/grub/fs.h	(revision 1989)
+++ include/grub/fs.h	(working copy)
@@ -27,6 +27,13 @@
 /* Forward declaration is required, because of mutual reference.  */
 struct grub_file;
 
+struct grub_dirhook_info
+{
+  int dir:1;
+  int mtimeset:1;
+  grub_int32_t mtime;
+};
+
 /* Filesystem descriptor.  */
 struct grub_fs
 {
@@ -35,7 +42,8 @@
 
   /* 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, 
+				  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 +64,9 @@
      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 1989)
+++ 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 1989)
+++ normal/completion.c	(working copy)
@@ -123,9 +123,9 @@
 }
 
 static int
-iterate_dir (const char *filename, int dir)
+iterate_dir (const char *filename, 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 1989)
+++ 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_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 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 @@
 {
   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 1989)
+++ 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 1989)
+++ 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,27 @@
   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, struct grub_dirhook_info info);
+  auto int print_files_long (const char *filename, 
+			     struct grub_dirhook_info info);
   
-  int print_files (const char *filename, int dir)
+  int print_files (const char *filename, 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, 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 +141,23 @@
       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,3 +200,4 @@
 	  /* 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 +215,11 @@
 	    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 1989)
+++ util/hostfs.c	(working copy)
@@ -57,7 +57,8 @@
 
 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, 
+			      struct grub_dirhook_info info))
 {
   DIR *dir;
 
@@ -73,16 +74,20 @@
   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 1989)
+++ ChangeLog	(working copy)
@@ -1,3 +1,67 @@
+2009-02-12  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/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/hfsplus.c (grub_hfsplus_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-09  Vladimir Serbinenko  <phcoder@gmail.com>
+
+	Bugfix: directories not reported as such on case-insensitive hfs+
+
+	* include/grub/fshelp.h: included definition of GRUB_FSHELP_TYPE_MASK 
+	and GRUB_FSHELP_FLAGS_MASK
+	* fs/hfsplus.c (grub_hfsplus_dir): ignore filetype flags
+
 2009-02-11  Robert Millan  <rmh@aybabtu.com>
 
 	* util/grub.d/00_header.in: Update old reference to `font' command.

  reply	other threads:[~2009-02-12 17:13 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-12 15:06 [PATCH] mtime support phcoder
2009-02-12 17:13 ` phcoder [this message]
2009-03-01 11:09   ` phcoder

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=499458BA.4010700@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.