65faf8
diff -urNp coreutils-8.21-orig/doc/coreutils.texi coreutils-8.21/doc/coreutils.texi
65faf8
--- coreutils-8.21-orig/doc/coreutils.texi	2013-02-11 10:37:28.000000000 +0100
65faf8
+++ coreutils-8.21/doc/coreutils.texi	2013-02-15 10:15:26.497593689 +0100
65faf8
@@ -10961,6 +10961,13 @@ pseudo-file-systems, such as automounter
65faf8
 Scale sizes by @var{size} before printing them (@pxref{Block size}).
65faf8
 For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes.
65faf8
 
65faf8
+@item --direct
65faf8
+@opindex --direct
65faf8
+@cindex direct statfs for a file
65faf8
+Do not resolve mount point and show statistics directly for a file. It can be
65faf8
+especially useful for NFS mount points if there is a boundary between two
65faf8
+storage policies behind the mount point.
65faf8
+
65faf8
 @item --total
65faf8
 @opindex --total
65faf8
 @cindex grand total of disk size, usage and available space
65faf8
diff -urNp coreutils-8.21-orig/src/df.c coreutils-8.21/src/df.c
65faf8
--- coreutils-8.21-orig/src/df.c	2013-02-05 00:40:31.000000000 +0100
65faf8
+++ coreutils-8.21/src/df.c	2013-02-15 10:26:41.158651782 +0100
65faf8
@@ -116,6 +116,9 @@ static bool print_type;
65faf8
 /* If true, print a grand total at the end.  */
65faf8
 static bool print_grand_total;
65faf8
 
65faf8
+/* If true, show statistics for a file instead of mount point.  */
65faf8
+static bool direct_statfs;
65faf8
+
65faf8
 /* Grand total data.  */
65faf8
 static struct fs_usage grand_fsu;
65faf8
 
65faf8
@@ -238,13 +241,15 @@ enum
65faf8
   NO_SYNC_OPTION = CHAR_MAX + 1,
65faf8
   SYNC_OPTION,
65faf8
   TOTAL_OPTION,
65faf8
-  OUTPUT_OPTION
65faf8
+  OUTPUT_OPTION,
65faf8
+  DIRECT_OPTION
65faf8
 };
65faf8
 
65faf8
 static struct option const long_options[] =
65faf8
 {
65faf8
   {"all", no_argument, NULL, 'a'},
65faf8
   {"block-size", required_argument, NULL, 'B'},
65faf8
+  {"direct", no_argument, NULL, DIRECT_OPTION},
65faf8
   {"inodes", no_argument, NULL, 'i'},
65faf8
   {"human-readable", no_argument, NULL, 'h'},
65faf8
   {"si", no_argument, NULL, 'H'},
65faf8
@@ -500,7 +505,10 @@ get_header (void)
65faf8
   for (col = 0; col < ncolumns; col++)
65faf8
     {
65faf8
       char *cell = NULL;
65faf8
-      char const *header = _(columns[col]->caption);
65faf8
+      char const *header = (columns[col]->field == TARGET_FIELD
65faf8
+                            && direct_statfs)?
65faf8
+                            _("File") :
65faf8
+                            _(columns[col]->caption);
65faf8
 
65faf8
       if (columns[col]->field == SIZE_FIELD
65faf8
           && (header_mode == DEFAULT_MODE
65faf8
@@ -1150,6 +1158,19 @@ get_point (const char *point, const stru
65faf8
 static void
65faf8
 get_entry (char const *name, struct stat const *statp)
65faf8
 {
65faf8
+  if (direct_statfs)
65faf8
+    {
65faf8
+      char *resolved = canonicalize_file_name (name);
65faf8
+      if (resolved)
65faf8
+	{
65faf8
+         char *mp = find_mount_point (name, statp);
65faf8
+	  get_dev (NULL, mp, resolved, NULL, NULL, false, false, NULL, false);
65faf8
+         free(mp);
65faf8
+	  free (resolved);
65faf8
+	  return;
65faf8
+	}
65faf8
+    }
65faf8
+
65faf8
   if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
65faf8
       && get_disk (name))
65faf8
     return;
65faf8
@@ -1219,6 +1238,7 @@ or all file systems by default.\n\
65faf8
   -B, --block-size=SIZE  scale sizes by SIZE before printing them; e.g.,\n\
65faf8
                            '-BM' prints sizes in units of 1,048,576 bytes;\n\
65faf8
                            see SIZE format below\n\
65faf8
+      --direct          show statistics for a file instead of mount point\n\
65faf8
       --total           produce a grand total\n\
65faf8
   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\
65faf8
 \n\
65faf8
@@ -1305,6 +1325,9 @@ main (int argc, char **argv)
65faf8
               xstrtol_fatal (e, oi, c, long_options, optarg);
65faf8
           }
65faf8
           break;
65faf8
+        case DIRECT_OPTION:
65faf8
+          direct_statfs = true;
65faf8
+          break;
65faf8
         case 'i':
65faf8
           if (header_mode == OUTPUT_MODE)
65faf8
             {
65faf8
@@ -1408,6 +1431,13 @@ main (int argc, char **argv)
65faf8
         }
65faf8
     }
65faf8
 
65faf8
+  if (direct_statfs && show_local_fs)
65faf8
+    {
65faf8
+      error (0, 0, _("options --direct and --local (-l) are mutually "
65faf8
+		     "exclusive"));
65faf8
+      usage (EXIT_FAILURE);
65faf8
+    }
65faf8
+
65faf8
   if (human_output_opts == -1)
65faf8
     {
65faf8
       if (posix_format)
65faf8
diff -urNp coreutils-8.21-orig/tests/df/direct.sh coreutils-8.21/tests/df/direct.sh
65faf8
--- coreutils-8.21-orig/tests/df/direct.sh	1970-01-01 01:00:00.000000000 +0100
65faf8
+++ coreutils-8.21/tests/df/direct.sh	2013-02-15 10:15:26.503644446 +0100
65faf8
@@ -0,0 +1,55 @@
65faf8
+#!/bin/sh
65faf8
+# Ensure "df --direct" works as documented
65faf8
+
65faf8
+# Copyright (C) 2010 Free Software Foundation, Inc.
65faf8
+
65faf8
+# This program is free software: you can redistribute it and/or modify
65faf8
+# it under the terms of the GNU General Public License as published by
65faf8
+# the Free Software Foundation, either version 3 of the License, or
65faf8
+# (at your option) any later version.
65faf8
+
65faf8
+# This program is distributed in the hope that it will be useful,
65faf8
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
65faf8
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
65faf8
+# GNU General Public License for more details.
65faf8
+
65faf8
+# You should have received a copy of the GNU General Public License
65faf8
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
65faf8
+
65faf8
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
65faf8
+print_ver_ df
65faf8
+
65faf8
+df || skip_ "df fails"
65faf8
+
65faf8
+DIR=`pwd` || framework_failure
65faf8
+FILE="$DIR/file"
65faf8
+touch "$FILE" || framework_failure
65faf8
+echo "$FILE" > file_exp || framework_failure
65faf8
+echo "Mounted on" > header_mounted_exp || framework_failure
65faf8
+echo "File" > header_file_exp || framework_failure
65faf8
+
65faf8
+fail=0
65faf8
+
65faf8
+df --portability "$FILE" > df_out || fail=1
65faf8
+df --portability --direct "$FILE" > df_direct_out || fail=1
65faf8
+df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1
65faf8
+
65faf8
+# check df header
65faf8
+$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \
65faf8
+  || framework_failure
65faf8
+$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \
65faf8
+  || framework_failure
65faf8
+compare header_mounted_out header_mounted_exp || fail=1
65faf8
+compare header_file_out header_file_exp || fail=1
65faf8
+
65faf8
+# check df output (without --direct)
65faf8
+$AWK '{ if (NR==2) print $6; }' df_out > file_out \
65faf8
+  || framework_failure
65faf8
+compare file_out file_exp && fail=1
65faf8
+
65faf8
+# check df output (with --direct)
65faf8
+$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \
65faf8
+  || framework_failure
65faf8
+compare file_out file_exp || fail=1
65faf8
+
65faf8
+Exit $fail