Kamil Dudka d05927
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
Kamil Dudka d05927
index fa21f03..7b8b622 100644
Kamil Dudka d05927
--- a/doc/coreutils.texi
Kamil Dudka d05927
+++ b/doc/coreutils.texi
Kamil Dudka d05927
@@ -10104,6 +10104,13 @@ pseudo-file-systems, such as automounter entries.
Kamil Dudka d05927
 Scale sizes by @var{size} before printing them (@pxref{Block size}).
Kamil Dudka d05927
 For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes.
Kamil Dudka d05927
 
Kamil Dudka d05927
+@itemx --direct
Kamil Dudka d05927
+@opindex --direct
Kamil Dudka d05927
+@cindex direct statfs for a file
Kamil Dudka d05927
+Do not resolve mount point and show statistics directly for a file. It can be
Kamil Dudka d05927
+especially useful for NFS mount points if there is a boundary between two
Kamil Dudka d05927
+storage policies behind the mount point.
Kamil Dudka d05927
+
Kamil Dudka d05927
 @itemx --total
Kamil Dudka d05927
 @opindex --total
Kamil Dudka d05927
 @cindex grand total of disk size, usage and available space
Kamil Dudka d05927
diff --git a/src/df.c b/src/df.c
Kamil Dudka d05927
index b862879..a74c353 100644
Kamil Dudka d05927
--- a/src/df.c
Kamil Dudka d05927
+++ b/src/df.c
Kamil Dudka d05927
@@ -110,6 +110,9 @@ static bool print_type;
Kamil Dudka d05927
 /* If true, print a grand total at the end.  */
Kamil Dudka d05927
 static bool print_grand_total;
Kamil Dudka d05927
 
Kamil Dudka d05927
+/* If true, show statistics for a file instead of mount point.  */
Kamil Dudka d05927
+static bool direct_statfs;
Kamil Dudka d05927
+
Kamil Dudka d05927
 /* Grand total data. */
Kamil Dudka d05927
 static struct fs_usage grand_fsu;
Kamil Dudka d05927
 
Kamil Dudka d05927
@@ -118,13 +121,15 @@ static struct fs_usage grand_fsu;
Kamil Dudka d05927
 enum
Kamil Dudka d05927
 {
Kamil Dudka d05927
   NO_SYNC_OPTION = CHAR_MAX + 1,
Kamil Dudka d05927
-  SYNC_OPTION
Kamil Dudka d05927
+  SYNC_OPTION,
Kamil Dudka d05927
+  DIRECT_OPTION
Kamil Dudka d05927
 };
Kamil Dudka d05927
 
Kamil Dudka d05927
 static struct option const long_options[] =
Kamil Dudka d05927
 {
Kamil Dudka d05927
   {"all", no_argument, NULL, 'a'},
Kamil Dudka d05927
   {"block-size", required_argument, NULL, 'B'},
Kamil Dudka d05927
+  {"direct", no_argument, NULL, DIRECT_OPTION},
Kamil Dudka d05927
   {"inodes", no_argument, NULL, 'i'},
Kamil Dudka d05927
   {"human-readable", no_argument, NULL, 'h'},
Kamil Dudka d05927
   {"si", no_argument, NULL, 'H'},
Kamil Dudka d05927
@@ -205,7 +210,10 @@ print_header (void)
Kamil Dudka d05927
               human_readable (output_block_size, buf, opts, 1, 1));
Kamil Dudka d05927
     }
Kamil Dudka d05927
 
Kamil Dudka d05927
-  fputs (_(" Mounted on\n"), stdout);
Kamil Dudka d05927
+  if (direct_statfs)
Kamil Dudka d05927
+    fputs (_(" File\n"), stdout);
Kamil Dudka d05927
+  else
Kamil Dudka d05927
+    fputs (_(" Mounted on\n"), stdout);
Kamil Dudka d05927
 }
Kamil Dudka d05927
 
Kamil Dudka d05927
 /* Is FSTYPE a type of file system that should be listed?  */
Kamil Dudka d05927
@@ -754,6 +762,17 @@ show_point (const char *point, const struct stat *statp)
Kamil Dudka d05927
 static void
Kamil Dudka d05927
 show_entry (char const *name, struct stat const *statp)
Kamil Dudka d05927
 {
Kamil Dudka d05927
+  if (direct_statfs)
Kamil Dudka d05927
+    {
Kamil Dudka d05927
+      char *resolved = canonicalize_file_name (name);
Kamil Dudka d05927
+      if (resolved)
Kamil Dudka d05927
+	{
Kamil Dudka d05927
+	  show_dev (NULL, resolved, NULL, NULL, false, false, NULL);
Kamil Dudka d05927
+	  free (resolved);
Kamil Dudka d05927
+	  return;
Kamil Dudka d05927
+	}
Kamil Dudka d05927
+    }
Kamil Dudka d05927
+
Kamil Dudka d05927
   if ((S_ISBLK (statp->st_mode) || S_ISCHR (statp->st_mode))
Kamil Dudka d05927
       && show_disk (name))
Kamil Dudka d05927
     return;
Kamil Dudka d05927
@@ -820,6 +839,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\
Kamil Dudka d05927
       fputs (_("\
Kamil Dudka d05927
   -a, --all             include dummy file systems\n\
Kamil Dudka d05927
   -B, --block-size=SIZE  use SIZE-byte blocks\n\
Kamil Dudka d05927
+      --direct          show statistics for a file instead of mount point\n\
Kamil Dudka d05927
       --total           produce a grand total\n\
Kamil Dudka d05927
   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 2G)\n\
Kamil Dudka d05927
   -H, --si              likewise, but use powers of 1000 not 1024\n\
Kamil Dudka d05927
@@ -894,6 +914,9 @@ main (int argc, char **argv)
Kamil Dudka d05927
               xstrtol_fatal (e, oi, c, long_options, optarg);
Kamil Dudka d05927
           }
Kamil Dudka d05927
           break;
Kamil Dudka d05927
+        case DIRECT_OPTION:
Kamil Dudka d05927
+          direct_statfs = true;
Kamil Dudka d05927
+          break;
Kamil Dudka d05927
         case 'i':
Kamil Dudka d05927
           inode_format = true;
Kamil Dudka d05927
           break;
Kamil Dudka d05927
@@ -954,6 +977,13 @@ main (int argc, char **argv)
Kamil Dudka d05927
         }
Kamil Dudka d05927
     }
Kamil Dudka d05927
 
Kamil Dudka d05927
+  if (direct_statfs && show_local_fs)
Kamil Dudka d05927
+    {
Kamil Dudka d05927
+      error (0, 0, _("options --direct and --local (-l) are mutually "
Kamil Dudka d05927
+		     "exclusive"));
Kamil Dudka d05927
+      usage (EXIT_FAILURE);
Kamil Dudka d05927
+    }
Kamil Dudka d05927
+
Kamil Dudka d05927
   if (human_output_opts == -1)
Kamil Dudka d05927
     {
Kamil Dudka d05927
       if (posix_format)
Kamil Dudka d05927
diff --git a/tests/Makefile.am b/tests/Makefile.am
Kamil Dudka d05927
index 1cb5a76..ab7abb4 100644
Kamil Dudka d05927
--- a/tests/Makefile.am
Kamil Dudka d05927
+++ b/tests/Makefile.am
Kamil Dudka d05927
@@ -328,6 +328,7 @@ TESTS =						\
Kamil Dudka d05927
   dd/stderr					\
Kamil Dudka d05927
   dd/unblock					\
Kamil Dudka d05927
   dd/unblock-sync				\
Kamil Dudka d05927
+  df/direct					\
Kamil Dudka d05927
   df/total-verify				\
Kamil Dudka d05927
   du/2g						\
Kamil Dudka d05927
   du/8gb					\
Kamil Dudka d05927
diff --git a/tests/df/direct b/tests/df/direct
Kamil Dudka d05927
new file mode 100644
Kamil Dudka d05927
index 0000000..9088f27
Kamil Dudka d05927
--- /dev/null
Kamil Dudka d05927
+++ b/tests/df/direct
Kamil Dudka d05927
@@ -0,0 +1,59 @@
Kamil Dudka d05927
+#!/bin/sh
Kamil Dudka d05927
+# Ensure "df --direct" works as documented
Kamil Dudka d05927
+
Kamil Dudka d05927
+# Copyright (C) 2010 Free Software Foundation, Inc.
Kamil Dudka d05927
+
Kamil Dudka d05927
+# This program is free software: you can redistribute it and/or modify
Kamil Dudka d05927
+# it under the terms of the GNU General Public License as published by
Kamil Dudka d05927
+# the Free Software Foundation, either version 3 of the License, or
Kamil Dudka d05927
+# (at your option) any later version.
Kamil Dudka d05927
+
Kamil Dudka d05927
+# This program is distributed in the hope that it will be useful,
Kamil Dudka d05927
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
Kamil Dudka d05927
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Kamil Dudka d05927
+# GNU General Public License for more details.
Kamil Dudka d05927
+
Kamil Dudka d05927
+# You should have received a copy of the GNU General Public License
Kamil Dudka d05927
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Kamil Dudka d05927
+
Kamil Dudka d05927
+if test "$VERBOSE" = yes; then
Kamil Dudka d05927
+  set -x
Kamil Dudka d05927
+  df --version
Kamil Dudka d05927
+fi
Kamil Dudka d05927
+
Kamil Dudka d05927
+. $srcdir/test-lib.sh
Kamil Dudka d05927
+
Kamil Dudka d05927
+df || skip_test_ "df fails"
Kamil Dudka d05927
+
Kamil Dudka d05927
+DIR=`pwd` || framework_failure
Kamil Dudka d05927
+FILE="$DIR/file"
Kamil Dudka d05927
+touch "$FILE" || framework_failure
Kamil Dudka d05927
+echo "$FILE" > file_exp || framework_failure
Kamil Dudka d05927
+echo "Mounted on" > header_mounted_exp || framework_failure
Kamil Dudka d05927
+echo "File" > header_file_exp || framework_failure
Kamil Dudka d05927
+
Kamil Dudka d05927
+fail=0
Kamil Dudka d05927
+
Kamil Dudka d05927
+df --portability "$FILE" > df_out || fail=1
Kamil Dudka d05927
+df --portability --direct "$FILE" > df_direct_out || fail=1
Kamil Dudka d05927
+df --portability --direct --local "$FILE" > /dev/null 2>&1 && fail=1
Kamil Dudka d05927
+
Kamil Dudka d05927
+# check df header
Kamil Dudka d05927
+$AWK '{ if (NR==1) print $6 " " $7; }' df_out > header_mounted_out \
Kamil Dudka d05927
+  || framework_failure
Kamil Dudka d05927
+$AWK '{ if (NR==1) print $6; }' df_direct_out > header_file_out \
Kamil Dudka d05927
+  || framework_failure
Kamil Dudka d05927
+compare header_mounted_out header_mounted_exp || fail=1
Kamil Dudka d05927
+compare header_file_out header_file_exp || fail=1
Kamil Dudka d05927
+
Kamil Dudka d05927
+# check df output (without --direct)
Kamil Dudka d05927
+$AWK '{ if (NR==2) print $6; }' df_out > file_out \
Kamil Dudka d05927
+  || framework_failure
Kamil Dudka d05927
+compare file_out file_exp && fail=1
Kamil Dudka d05927
+
Kamil Dudka d05927
+# check df output (with --direct)
Kamil Dudka d05927
+$AWK '{ if (NR==2) print $6; }' df_direct_out > file_out \
Kamil Dudka d05927
+  || framework_failure
Kamil Dudka d05927
+compare file_out file_exp || fail=1
Kamil Dudka d05927
+
Kamil Dudka d05927
+Exit $fail