50a3bad
diff -urNp coreutils-8.11-orig/doc/coreutils.texi coreutils-8.11/doc/coreutils.texi
50a3bad
--- coreutils-8.11-orig/doc/coreutils.texi	2011-04-12 12:07:43.000000000 +0200
50a3bad
+++ coreutils-8.11/doc/coreutils.texi	2011-04-14 09:53:43.764309420 +0200
50a3bad
@@ -10409,6 +10409,13 @@ pseudo-file-systems, such as automounter
d059274
 Scale sizes by @var{size} before printing them (@pxref{Block size}).
d059274
 For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes.
d059274
 
d059274
+@itemx --direct
d059274
+@opindex --direct
d059274
+@cindex direct statfs for a file
d059274
+Do not resolve mount point and show statistics directly for a file. It can be
d059274
+especially useful for NFS mount points if there is a boundary between two
d059274
+storage policies behind the mount point.
d059274
+
d059274
 @itemx --total
d059274
 @opindex --total
d059274
 @cindex grand total of disk size, usage and available space
50a3bad
diff -urNp coreutils-8.11-orig/src/df.c coreutils-8.11/src/df.c
50a3bad
--- coreutils-8.11-orig/src/df.c	2011-04-12 12:07:43.000000000 +0200
50a3bad
+++ coreutils-8.11/src/df.c	2011-04-14 10:37:44.208308771 +0200
50a3bad
@@ -112,6 +112,9 @@ static bool print_type;
d059274
 /* If true, print a grand total at the end.  */
d059274
 static bool print_grand_total;
d059274
 
d059274
+/* If true, show statistics for a file instead of mount point.  */
d059274
+static bool direct_statfs;
d059274
+
d059274
 /* Grand total data. */
d059274
 static struct fs_usage grand_fsu;
d059274
 
50a3bad
@@ -166,13 +169,15 @@ static size_t nrows;
d059274
 enum
d059274
 {
d059274
   NO_SYNC_OPTION = CHAR_MAX + 1,
d059274
-  SYNC_OPTION
d059274
+  SYNC_OPTION,
d059274
+  DIRECT_OPTION
d059274
 };
d059274
 
d059274
 static struct option const long_options[] =
d059274
 {
d059274
   {"all", no_argument, NULL, 'a'},
d059274
   {"block-size", required_argument, NULL, 'B'},
d059274
+  {"direct", no_argument, NULL, DIRECT_OPTION},
d059274
   {"inodes", no_argument, NULL, 'i'},
d059274
   {"human-readable", no_argument, NULL, 'h'},
d059274
   {"si", no_argument, NULL, 'H'},
50a3bad
@@ -259,7 +264,11 @@ get_header (void)
50a3bad
         }
d059274
 
50a3bad
       char *cell = NULL;
50a3bad
-      char const *header = _(headers[field][header_mode]);
50a3bad
+     
50a3bad
+      char const *header = (field == MNT_FIELD && direct_statfs)?
d79f57c
+                             _("File") :
50a3bad
+                             _(headers[field][header_mode]);
50a3bad
+
50a3bad
       if (!header)
50a3bad
         header = _(headers[field][DEFAULT_MODE]);
d059274
 
50a3bad
@@ -757,6 +766,17 @@ get_point (const char *point, const stru
d059274
 static void
50a3bad
 get_entry (char const *name, struct stat const *statp)
d059274
 {
d059274
+  if (direct_statfs)
d059274
+    {
d059274
+      char *resolved = canonicalize_file_name (name);
d059274
+      if (resolved)
d059274
+	{
50a3bad
+	  get_dev (NULL, resolved, NULL, NULL, false, false, NULL);
d059274
+	  free (resolved);
d059274
+	  return;
d059274
+	}
d059274
+    }
d059274
+
d059274
   if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
50a3bad
       && get_disk (name))
d059274
     return;
50a3bad
@@ -825,6 +845,7 @@ Mandatory arguments to long options are 
98ff9fe
   -B, --block-size=SIZE  scale sizes by SIZE before printing them.  E.g.,\n\
98ff9fe
                            `-BM' prints sizes in units of 1,048,576 bytes.\n\
98ff9fe
                            See SIZE format below.\n\
d059274
+      --direct          show statistics for a file instead of mount point\n\
d059274
       --total           produce a grand total\n\
58ba6d5
   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\
58ba6d5
 \n\
50a3bad
@@ -901,6 +922,9 @@ main (int argc, char **argv)
d059274
               xstrtol_fatal (e, oi, c, long_options, optarg);
d059274
           }
d059274
           break;
d059274
+        case DIRECT_OPTION:
d059274
+          direct_statfs = true;
d059274
+          break;
d059274
         case 'i':
d059274
           inode_format = true;
d059274
           break;
50a3bad
@@ -961,6 +985,13 @@ main (int argc, char **argv)
d059274
         }
d059274
     }
d059274
 
d059274
+  if (direct_statfs && show_local_fs)
d059274
+    {
d059274
+      error (0, 0, _("options --direct and --local (-l) are mutually "
d059274
+		     "exclusive"));
d059274
+      usage (EXIT_FAILURE);
d059274
+    }
d059274
+
d059274
   if (human_output_opts == -1)
d059274
     {
d059274
       if (posix_format)
50a3bad
diff -urNp coreutils-8.11-orig/tests/df/direct coreutils-8.11/tests/df/direct
50a3bad
--- coreutils-8.11-orig/tests/df/direct	1970-01-01 01:00:00.000000000 +0100
50a3bad
+++ coreutils-8.11/tests/df/direct	2011-04-14 09:53:43.767400034 +0200
826eac7
@@ -0,0 +1,55 @@
d059274
+#!/bin/sh
d059274
+# Ensure "df --direct" works as documented
d059274
+
d059274
+# Copyright (C) 2010 Free Software Foundation, Inc.
d059274
+
d059274
+# This program is free software: you can redistribute it and/or modify
d059274
+# it under the terms of the GNU General Public License as published by
d059274
+# the Free Software Foundation, either version 3 of the License, or
d059274
+# (at your option) any later version.
d059274
+
d059274
+# This program is distributed in the hope that it will be useful,
d059274
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
d059274
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d059274
+# GNU General Public License for more details.
d059274
+
d059274
+# You should have received a copy of the GNU General Public License
d059274
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
d059274
+
826eac7
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
826eac7
+print_ver_ df
d059274
+
d059274
+df || skip_test_ "df fails"
d059274
+
d059274
+DIR=`pwd` || framework_failure
d059274
+FILE="$DIR/file"
d059274
+touch "$FILE" || framework_failure
d059274
+echo "$FILE" > file_exp || framework_failure
d059274
+echo "Mounted on" > header_mounted_exp || framework_failure
d059274
+echo "File" > header_file_exp || framework_failure
d059274
+
d059274
+fail=0
d059274
+
d059274
+df --portability "$FILE" > df_out || fail=1
d059274
+df --portability --direct "$FILE" > df_direct_out || fail=1
d059274
+df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1
d059274
+
d059274
+# check df header
d059274
+$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \
d059274
+  || framework_failure
d059274
+$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \
d059274
+  || framework_failure
d059274
+compare header_mounted_out header_mounted_exp || fail=1
d059274
+compare header_file_out header_file_exp || fail=1
d059274
+
d059274
+# check df output (without --direct)
d79f57c
+$AWK '{ if (NR==2) print $6; }' df_out > file_out \
d79f57c
+  || framework_failure
d79f57c
+compare file_out file_exp && fail=1
d059274
+
d059274
+# check df output (with --direct)
d79f57c
+$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \
d79f57c
+  || framework_failure
d79f57c
+compare file_out file_exp || fail=1
d059274
+
d059274
+Exit $fail
50a3bad
diff -urNp coreutils-8.11-orig/tests/Makefile.am coreutils-8.11/tests/Makefile.am
50a3bad
--- coreutils-8.11-orig/tests/Makefile.am	2011-04-14 09:53:13.666324768 +0200
50a3bad
+++ coreutils-8.11/tests/Makefile.am	2011-04-14 09:53:43.768432620 +0200
50a3bad
@@ -362,6 +362,7 @@ TESTS =						\
58ba6d5
   dd/stderr					\
58ba6d5
   dd/unblock					\
58ba6d5
   dd/unblock-sync				\
58ba6d5
+  df/direct					\
58ba6d5
   df/total-verify				\
58ba6d5
   du/2g						\
58ba6d5
   du/8gb					\