bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Suggested enhancement to du command - show last modified date.


From: William Brendling
Subject: Re: Suggested enhancement to du command - show last modified date.
Date: Wed, 8 Jun 2005 19:28:36 +0100

The following patch is my fist iteration at implementing my suggested
"--last-modified" option for "du". It is a simple port of my original
draft code to the latest CVS source for "du".

> >> Doesn't the standard ISO-8601 date format accomplish that, too?

I have changed the default date format to be ISO-8601 (I think).

> >> Writing ChangeLog entries describing your changes is helpful.
> >> It's good to update the --help output and even better to update
> >> the primary documentation in the file doc/coreutils.texi.

I have added ChangeLog entries. I have also had a go at the
coreutils.texi file, but I don't really know what I am doing here.
Guess and hope.

Plans for the next iteration, if I find the time:

> >> It might be nice to have an option that makes it look
> >> at atime rather than mtime.

* Implement Jim Meyering's suggested improvements.

* From a coding point of view, it would be better if the per-directory
level variables (sum_ent, sum_subdir, dmax_ent, dmax_subdir) were in a
structure, requiring only one alloc/realloc, rather than the four
currently used. My excuse is that the original code already had two
alloc/reallocs.

Patch follows:

Index: coreutils/ChangeLog
===================================================================
RCS file: /cvsroot/coreutils/coreutils/ChangeLog,v
retrieving revision 1.1314
diff -u -r1.1314 ChangeLog
--- coreutils/ChangeLog 2 Jun 2005 10:04:32 -0000       1.1314
+++ coreutils/ChangeLog 8 Jun 2005 17:38:45 -0000
@@ -1,3 +1,7 @@
+2005-06-06  William Brendling  <address@hidden>
+
+       * src/du.c: Added --last-modified switch.
+
 2005-06-02  Jim Meyering  <address@hidden>
 
        * Version 5.3.1.
Index: coreutils/doc/ChangeLog
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/ChangeLog,v
retrieving revision 1.237
diff -u -r1.237 ChangeLog
--- coreutils/doc/ChangeLog     2 Jun 2005 05:00:50 -0000       1.237
+++ coreutils/doc/ChangeLog     8 Jun 2005 17:39:54 -0000
@@ -1,3 +1,7 @@
+2005-06-06  William Brendling  <address@hidden>
+
+       * coreutils.texi (du invocation): New flag --last-modified.
+
 2005-06-01  Paul Eggert  <address@hidden>
 
        Use "file name" when talking about file names, instead of "filename"
Index: coreutils/doc/coreutils.texi
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/coreutils.texi,v
retrieving revision 1.259
diff -u -r1.259 coreutils.texi
--- coreutils/doc/coreutils.texi        2 Jun 2005 05:00:24 -0000       1.259
+++ coreutils/doc/coreutils.texi        8 Jun 2005 17:40:13 -0000
@@ -9006,6 +9006,18 @@
 or directory that the link points to instead of the space used by
 the link).
 
address@hidden address@hidden
address@hidden address@hidden
address@hidden last modified dates, displaying in @command{du}
+Show the most recent last modified date of any of the files in the
+directory or sub-directories.
+Optionally format header dates using @var{format}, using the same
conventions as
+for the the command @samp{date address@hidden; @xref{date invocation}.
+Except for directives, which start with
address@hidden, characters in @var{format} are printed unchanged.  You can use
+this option to specify an arbitrary string in place of the header date,
+e.g., @option{--date-format="Monday morning"}.
+
 @item -P
 @itemx --no-dereference
 @opindex -P
Index: coreutils/src/du.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/du.c,v
retrieving revision 1.203
diff -u -r1.203 du.c
--- coreutils/src/du.c  2 Jun 2005 05:17:24 -0000       1.203
+++ coreutils/src/du.c  8 Jun 2005 17:40:21 -0000
@@ -29,13 +29,13 @@
 #include <getopt.h>
 #include <sys/types.h>
 #include <assert.h>
-
 #include "system.h"
 #include "dirname.h" /* for strip_trailing_slashes */
 #include "error.h"
 #include "exclude.h"
 #include "hash.h"
 #include "human.h"
+#include "inttostr.h"
 #include "quote.h"
 #include "quotearg.h"
 #include "readtokens0.h"
@@ -104,14 +104,19 @@
 /* Human-readable options for output.  */
 static int human_output_opts;
 
+/* If option non-zero, print most recently modified date, using the
specified format */
+static int opt_last_modified = 0;
+static char *format = NULL;
+
 /* The units to use when printing sizes.  */
 static uintmax_t output_block_size;
 
 /* File name patterns to exclude.  */
 static struct exclude *exclude;
 
-/* Grand total size of all args, in bytes. */
+/* Grand total size of all args, in bytes. Also latist modified date. */
 static uintmax_t tot_size = 0;
+static time_t tot_dmax = 0;
 
 #define IS_DIR_TYPE(Type)      \
   ((Type) == FTS_DP            \
@@ -125,7 +130,8 @@
   EXCLUDE_OPTION,
   FILES0_FROM_OPTION,
   HUMAN_SI_OPTION,
-  MAX_DEPTH_OPTION
+  MAX_DEPTH_OPTION,
+  LAST_MODIFIED_OPTION
 };
 
 static struct option const long_options[] =
@@ -151,6 +157,7 @@
   {"separate-dirs", no_argument, NULL, 'S'},
   {"summarize", no_argument, NULL, 's'},
   {"total", no_argument, NULL, 'c'},
+  {"last-modified", optional_argument, NULL, LAST_MODIFIED_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -212,6 +219,12 @@
                           line argument;  --max-depth=0 is the same as\n\
                           --summarize\n\
 "), stdout);
+      fputs (_("\
+      --last-modified    Print date of most recently modified file in
default format\n\
+                         YYYY/MM/DD.HH:MM. Text order is same as date order.\n\
+      --last-modified=FORMAT   Print date of most recently modified
file in specified\n\
+                               format. See \"date\" command for
syntax of format string.\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       fputs (_("\n\
@@ -285,6 +298,60 @@
     xalloc_die ();
 }
 
+/* Display the date and/or time in WHEN according to the format specified
+   in FORMAT, followed by a newline.  If FORMAT is NULL, use the
+   standard output format. Return zero if successful.
+
+   Hacked from the similarly named routine in "date".
+*/
+
+static int
+show_date (const char *format, time_t when)
+{
+  struct tm *tm;
+  char *out = NULL;
+  size_t out_length = 0;
+
+  if ((format == NULL)||(*format == '\0'))
+    {
+      format = "%Y-%m-%dT%H:%M:%S"; 
+    }
+
+  tm = localtime (&when);
+  if (! tm)
+    {
+      char buf[INT_BUFSIZE_BOUND (intmax_t)];
+      error (0, 0, _("time %s is out of range"),
+            (TYPE_SIGNED (time_t)
+             ? imaxtostr (when, buf)
+             : umaxtostr (when, buf)));
+      puts (buf);
+      return 1;
+    }
+
+  while (1)
+    {
+      int done;
+      out = x2nrealloc (out, &out_length, sizeof *out);
+
+      /* Mark the first byte of the buffer so we can detect the case
+        of nstrftime producing an empty string.  Otherwise, this loop
+        would not terminate when date was invoked like this
+        `LANG=de date +%p' on a system with good language support.  */
+      out[0] = '\1';
+
+      done = (nstrftime (out, out_length, format, tm, 0, when)
+             || out[0] == '\0');
+
+      if (done)
+       break;
+    }
+
+  fputs (out,stdout);
+  free (out);
+  return 0;
+}
+
 /* Print N_BYTES.  Convert it to a readable value before printing.  */
 
 static void
@@ -296,12 +363,18 @@
 }
 
 /* Print N_BYTES followed by STRING on a line.
+   Optionally include last modified date.
    Convert N_BYTES to a readable value before printing.  */
 
 static void
-print_size (uintmax_t n_bytes, const char *string)
+print_size (uintmax_t n_bytes, time_t when, const char *string)
 {
   print_only_size (n_bytes);
+  if ( opt_last_modified )
+    {
+      putchar ('\t');
+      show_date (format, when);
+    }
   printf ("\t%s%c", string, opt_nul_terminate_output ? '\0' : '\n');
   fflush (stdout);
 }
@@ -316,19 +389,23 @@
 {
   bool ok;
   uintmax_t size;
+  time_t dmax;
   uintmax_t size_to_print;
+  time_t dmax_to_print;
   size_t level;
   static size_t prev_level;
   static size_t n_alloc;
   /* The sum of the st_size values of all entries in the single directory
      at the corresponding level.  Although this does include the st_size
      corresponding to each subdirectory, it does not include the size of
-     any file in a subdirectory.  */
+     any file in a subdirectory. Also corresponding last modified date. */
   static uintmax_t *sum_ent;
+  static time_t *dmax_ent;
 
   /* The sum of the sizes of all entries in the hierarchy at or below the
      directory at the specified level.  */
   static uintmax_t *sum_subdir;
+  static time_t *dmax_subdir;
   bool print = true;
 
   const char *file = ent->fts_path;
@@ -381,6 +458,7 @@
         We still have to update prev_level and maybe propagate
         some sums up the hierarchy.  */
       size = 0;
+      dmax = 0;
       print = false;
     }
   else
@@ -388,16 +466,20 @@
       size = (apparent_size
              ? sb->st_size
              : ST_NBLOCKS (*sb) * ST_NBLOCKSIZE);
+      dmax = sb->st_mtime;
     }
 
   level = ent->fts_level;
   size_to_print = size;
+  dmax_to_print = dmax;
 
   if (n_alloc == 0)
     {
       n_alloc = level + 10;
       sum_ent = xcalloc (n_alloc, sizeof *sum_ent);
       sum_subdir = xcalloc (n_alloc, sizeof *sum_subdir);
+      dmax_ent = xcalloc (n_alloc, sizeof *dmax_ent);
+      dmax_subdir = xcalloc (n_alloc, sizeof *dmax_subdir);
     }
   else
     {
@@ -418,13 +500,17 @@
              sum_ent = xnrealloc (sum_ent, level, 2 * sizeof *sum_ent);
              sum_subdir = xnrealloc (sum_subdir, level,
                                      2 * sizeof *sum_subdir);
+         dmax_ent = xnrealloc (dmax_ent, level, 2 * sizeof *dmax_ent);
+         dmax_subdir = xnrealloc (dmax_subdir, level, 2 * sizeof *dmax_subdir);
              n_alloc = level * 2;
            }
 
          for (i = prev_level + 1; i <= level; i++)
            {
              sum_ent[i] = 0;
+         dmax_ent[i] = 0;
              sum_subdir[i] = 0;
+         dmax_subdir[i] = 0;
            }
        }
       else /* level < prev_level */
@@ -437,9 +523,18 @@
             previous one.  */
          assert (level == prev_level - 1);
          size_to_print += sum_ent[prev_level];
+     if ( dmax_ent[prev_level] > dmax_to_print ) dmax_to_print =
dmax_ent[prev_level];
          if (!opt_separate_dirs)
-           size_to_print += sum_subdir[prev_level];
+       {
+         size_to_print += sum_subdir[prev_level];
+         if ( dmax_subdir[prev_level] > dmax_to_print )
+            dmax_to_print = dmax_subdir[prev_level];
+       }
          sum_subdir[level] += sum_ent[prev_level] + sum_subdir[prev_level];
+     if ( dmax_ent[prev_level] > dmax_subdir[level] )
+       dmax_subdir[level] = dmax_ent[prev_level];
+     if ( dmax_subdir[prev_level] > dmax_subdir[level] )
+       dmax_subdir[level] = dmax_subdir[prev_level];
        }
     }
 
@@ -448,11 +543,15 @@
   /* Let the size of a directory entry contribute to the total for the
      containing directory, unless --separate-dirs (-S) is specified.  */
   if ( ! (opt_separate_dirs && IS_DIR_TYPE (ent->fts_info)))
-    sum_ent[level] += size;
+    {
+      sum_ent[level] += size;
+      if ( dmax > dmax_ent[level] ) dmax_ent[level] = dmax;
+    }
 
   /* Even if this directory is unreadable or we can't chdir into it,
      do let its size contribute to the total, ... */
   tot_size += size;
+  if ( dmax > tot_dmax ) tot_dmax = dmax;
 
   /* ... but don't print out a total for it, since without the size(s)
      of any potential entries, it could be very misleading.  */
@@ -468,11 +567,7 @@
   if ((IS_DIR_TYPE (ent->fts_info) && level <= max_depth)
       || ((opt_all && level <= max_depth) || level == 0))
     {
-      print_only_size (size_to_print);
-      fputc ('\t', stdout);
-      fputs (file, stdout);
-      fputc (opt_nul_terminate_output ? '\0' : '\n', stdout);
-      fflush (stdout);
+      print_size (size_to_print, dmax_to_print, file);
     }
 
   return ok;
@@ -519,7 +614,7 @@
     }
 
   if (print_grand_total)
-    print_size (tot_size, _("total"));
+    print_size (tot_size, tot_dmax, _("total"));
 
   return ok;
 }
@@ -681,6 +776,11 @@
          add_exclude (exclude, optarg, EXCLUDE_WILDCARDS);
          break;
 
+   case LAST_MODIFIED_OPTION:
+      opt_last_modified = 1;
+      format = optarg;
+      break;
+
        case_GETOPT_HELP_CHAR;
 
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]