bug-coreutils
[Top][All Lists]
Advanced

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

Re: bug in du --time=atime


From: William Brendling
Subject: Re: bug in du --time=atime
Date: Tue, 4 Oct 2005 20:26:17 +0100

On 6/24/05, Paul Eggert <address@hidden> wrote:
> A problem that I just noticed with the recent change to "du" is that
> "du --time=atime" always reports the current time, for all entries.
> This is because du reads each directory first, before it stats it,
> which means the directory's last-accessed time is always the current
> time.

The following patch resolves this issue. For directories, the atime is
collected during the first pass from FTS, prior to desending the
directory tree.

> Or (this may be better), how about an option that restores atime
> after the directory is read?

The new option --preserve-atime does this. When assending the
directory tree, it resets the directoy atime to that obtained prior to
descending the tree. This option works irrespective of which time is
being displayed, or even if no times are being output.

A couple of implementation notes:

I found that ent->fts_statp->stime was always zero during the
pre-descent pass. I am not sure whether this is because I have an old
version of FTS. To resolve this, I make an explicit stat call for the
directory.

The code would be neater if there is an equivalent of utimes that
accepts "strut timespec" instead of "struct timeval". I am not aware
of a suitable routine, but perhaps someone can suggest one.

Index: coreutils/ChangeLog
===================================================================
RCS file: /cvsroot/coreutils/coreutils/ChangeLog,v
retrieving revision 1.1488
diff -u -r1.1488 ChangeLog
--- coreutils/ChangeLog 3 Oct 2005 12:12:21 -0000       1.1488
+++ coreutils/ChangeLog 4 Oct 2005 18:59:19 -0000
@@ -1,3 +1,9 @@
+2005-06-14  William Brendling  <address@hidden>
+
+       * src/du.c: Add --preserve-atime option.
+       When using --time=atime option, use directory atime prior to descent
+       rather than after descent.
+
 2005-10-03  Jim Meyering  <address@hidden>

        * Version 5.91-cvs.
Index: coreutils/doc/ChangeLog
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/ChangeLog,v
retrieving revision 1.258
diff -u -r1.258 ChangeLog
--- coreutils/doc/ChangeLog     25 Sep 2005 06:11:45 -0000      1.258
+++ coreutils/doc/ChangeLog     4 Oct 2005 18:59:21 -0000
@@ -1,3 +1,7 @@
+2005-10-04  William Brendling  <address@hidden>
+
+       * coreutils.texi (du invocation): New option --preserve-atime.
+
 2005-09-24  Paul Eggert  <address@hidden>

        * coreutils.texi (touch invocation):
Index: coreutils/doc/coreutils.texi
===================================================================
RCS file: /cvsroot/coreutils/coreutils/doc/coreutils.texi,v
retrieving revision 1.285
diff -u -r1.285 coreutils.texi
--- coreutils/doc/coreutils.texi        25 Sep 2005 06:08:17 -0000      1.285
+++ coreutils/doc/coreutils.texi        4 Oct 2005 18:59:36 -0000
@@ -9028,6 +9028,13 @@
 This option enables other programs to parse the output of @command{du}
 even when that output would contain file names with embedded newlines.

address@hidden --preserve-atime
address@hidden --preserve-atime
address@hidden directory access dates, preserving in @command{du}
+The @command{du} program normally changes the access time of each of the
+directories it traverses. This option causes @command{du} to reset the
+directory access time to its previous value after traversal.
+
 @itemx --si
 @opindex --si
 @cindex SI output
Index: coreutils/src/du.c
===================================================================
RCS file: /cvsroot/coreutils/coreutils/src/du.c,v
retrieving revision 1.222
diff -u -r1.222 du.c
--- coreutils/src/du.c  16 Sep 2005 08:08:32 -0000      1.222
+++ coreutils/src/du.c  4 Oct 2005 18:59:38 -0000
@@ -77,6 +77,16 @@
 /* A set of dev/ino pairs.  */
 static Hash_table *htab;

+/* Conversion from timespec to timeval */
+static inline struct timeval
+timespec2timeval (struct timespec ts)
+{
+  struct timeval tv;
+  tv.tv_sec = (long) ts.tv_sec;
+  tv.tv_usec = ts.tv_nsec / 1000;
+  return tv;
+}
+
 /* Define a class for collecting directory information. */

 struct duinfo
@@ -123,6 +133,9 @@

   /* Total for subdirectories.  */
   struct duinfo subdir;
+
+  /* Pre-traverse atime.       */
+  struct timespec at_prev;
 };

 /* Name under which this program was invoked.  */
@@ -175,6 +188,9 @@
 /* Format used to display date / time. Controlled by --time-style */
 static char const *time_format = NULL;

+/* Restore directory atime after traversal.    */
+static bool preserve_atime;
+
 /* The units to use when printing sizes.  */
 static uintmax_t output_block_size;

@@ -198,7 +214,8 @@
   HUMAN_SI_OPTION,
   MAX_DEPTH_OPTION,
   TIME_OPTION,
-  TIME_STYLE_OPTION
+  TIME_STYLE_OPTION,
+  PRESERVE_ATIME_OPTION
 };

 static struct option const long_options[] =
@@ -226,6 +243,7 @@
   {"total", no_argument, NULL, 'c'},
   {"time", optional_argument, NULL, TIME_OPTION},
   {"time-style", required_argument, NULL, TIME_STYLE_OPTION},
+  {"preserve-atime", no_argument, NULL, PRESERVE_ATIME_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -325,6 +343,9 @@
       --time-style=STYLE show times using style STYLE:\n\
                           full-iso, long-iso, iso, +FORMAT\n\
                           FORMAT is interpreted like `date'\n\
+      --preserve-atime  preserve the original atime of the
directories traversed.\n\
+                          By default the atime is set to current time as the\n\
+                          directories are read.
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -503,12 +524,40 @@
       break;
     }

-  /* If this is the first (pre-order) encounter with a directory,
-     or if it's the second encounter for a skipped directory, then
+  /* If this is the second encounter for a skipped directory, then
      return right away.  */
-  if (ent->fts_info == FTS_D || skip)
+  if (skip)
     return ok;

+  /* If we don't need to obtain the atime of a directory in pre-order,
+     return before allocating storage. */
+  if ( (ent->fts_info == FTS_D) && (! preserve_atime) && (time_type
!= time_atime) )
+    return ok;
+
+  /* Allocate storage for additional levels if required.       */
+
+  level = ent->fts_level;
+  if (n_alloc == 0)
+    {
+      n_alloc = level + 10;
+      dulvl = xcalloc (n_alloc, sizeof *dulvl);
+    }
+  else if (n_alloc <= level)
+    {
+      dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl);
+      n_alloc = level * 2;
+    }
+
+  /* If this is the first (pre-order) encounter with a directory,
+     then collect atime and return.  */
+  if (ent->fts_info == FTS_D)
+    {
+      struct stat stdir;
+      stat (ent->fts_accpath, &stdir);
+      dulvl[level].at_prev = get_stat_atime (&stdir);
+      return ok;
+    }
+
   /* If the file is being excluded or if it has already been counted
      via a hard link, then don't let it contribute to the sums.  */
   if (skip
@@ -530,63 +579,59 @@
                   ? sb->st_size
                   : ST_NBLOCKS (*sb) * ST_NBLOCKSIZE),
                  (time_type == time_mtime ? get_stat_mtime (sb)
-                  : time_type == time_atime ? get_stat_atime (sb)
+                  : time_type == time_atime ? ( ent->fts_info == FTS_DP ?
+                       dulvl[level].at_prev : get_stat_atime (sb) )
                   : get_stat_ctime (sb)));
     }

-  level = ent->fts_level;
   dui_to_print = dui;

-  if (n_alloc == 0)
+  if (level == prev_level)
     {
-      n_alloc = level + 10;
-      dulvl = xcalloc (n_alloc, sizeof *dulvl);
+      /* This is usually the most common case.  Do nothing.  */
     }
-  else
+  else if (level > prev_level)
     {
-      if (level == prev_level)
-       {
-         /* This is usually the most common case.  Do nothing.  */
-       }
-      else if (level > prev_level)
-       {
-         /* Descending the hierarchy.
-            Clear the accumulators for *all* levels between prev_level
-            and the current one.  The depth may change dramatically,
-            e.g., from 1 to 10.  */
-         size_t i;
-
-         if (n_alloc <= level)
-           {
-             dulvl = xnrealloc (dulvl, level, 2 * sizeof *dulvl);
-             n_alloc = level * 2;
-           }
+      /* Descending the hierarchy.
+          Clear the accumulators for *all* levels between prev_level
+          and the current one.  The depth may change dramatically,
+          e.g., from 1 to 10.  */
+      size_t i;

-         for (i = prev_level + 1; i <= level; i++)
-           {
-             duinfo_init (&dulvl[i].ent);
-             duinfo_init (&dulvl[i].subdir);
-           }
-       }
-      else /* level < prev_level */
+      for (i = prev_level + 1; i <= level; i++)
        {
-         /* Ascending the hierarchy.
-            Process a directory only after all entries in that
-            directory have been processed.  When the depth decreases,
-            propagate sums from the children (prev_level) to the parent.
-            Here, the current level is always one smaller than the
-            previous one.  */
-         assert (level == prev_level - 1);
-         duinfo_add (&dui_to_print, &dulvl[prev_level].ent);
-         if (!opt_separate_dirs)
-           duinfo_add (&dui_to_print, &dulvl[prev_level].subdir);
-         duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].ent);
-         duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].subdir);
+         duinfo_init (&dulvl[i].ent);
+         duinfo_init (&dulvl[i].subdir);
        }
     }
+  else /* level < prev_level */
+    {
+      /* Ascending the hierarchy.
+          Process a directory only after all entries in that
+          directory have been processed.  When the depth decreases,
+          propagate sums from the children (prev_level) to the parent.
+          Here, the current level is always one smaller than the
+          previous one.  */
+       assert (level == prev_level - 1);
+       duinfo_add (&dui_to_print, &dulvl[prev_level].ent);
+       if (!opt_separate_dirs)
+         duinfo_add (&dui_to_print, &dulvl[prev_level].subdir);
+       duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].ent);
+       duinfo_add (&dulvl[level].subdir, &dulvl[prev_level].subdir);
+    }

   prev_level = level;

+  /* Reset directory atime if required.        */
+  if ( preserve_atime && ( ent->fts_info == FTS_DP ))
+    {
+    struct timeval tvdir[2];
+    tvdir[0] = timespec2timeval (dulvl[level].at_prev);
+    tvdir[1] = timespec2timeval (get_stat_mtime (sb));
+    if ( utimes (ent->fts_accpath, tvdir) )
+      error (0, errno, _("failed to restore atime of %s"), quote (file));
+    }
+
   /* 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)))
@@ -827,6 +872,10 @@

        case TIME_STYLE_OPTION:
          time_style = optarg;
+         break;
+
+       case PRESERVE_ATIME_OPTION:
+         preserve_atime = true;
          break;

        case_GETOPT_HELP_CHAR;




reply via email to

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