diff --git a/libraries/base/configure.ac b/libraries/base/configure.ac
index 55a5df9d9549886291e0d7494621c0cb1f9afe45..f27a03439501a5cbed2943118fe9a12f90a3d7fc 100644
--- a/libraries/base/configure.ac
+++ b/libraries/base/configure.ac
@@ -141,8 +141,11 @@ then
   FP_COMPUTE_OFFSET([OFFSET_STAT_ST_BLOCKS],  [stat], [st_blocks],  [#include <sys/stat.h>])
   FP_COMPUTE_OFFSET([OFFSET_STAT_ST_INO],     [stat], [st_ino],     [#include <sys/stat.h>])
   FP_COMPUTE_OFFSET([OFFSET_STAT_ST_ATIME],   [stat], [st_atime],   [#include <sys/stat.h>])
+  FP_COMPUTE_OFFSET([OFFSET_STAT_ST_ATIM_TV_NSEC],   [stat], [st_atim.tv_nsec],   [#include <sys/stat.h>])
   FP_COMPUTE_OFFSET([OFFSET_STAT_ST_MTIME],   [stat], [st_mtime],   [#include <sys/stat.h>])
+  FP_COMPUTE_OFFSET([OFFSET_STAT_ST_MTIM_TV_NSEC],   [stat], [st_mtim.tv_nsec],   [#include <sys/stat.h>])
   FP_COMPUTE_OFFSET([OFFSET_STAT_ST_CTIME],   [stat], [st_ctime],   [#include <sys/stat.h>])
+  FP_COMPUTE_OFFSET([OFFSET_STAT_ST_CTIM_TV_NSEC],   [stat], [st_ctim.tv_nsec],   [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_MODE],    [stat], [st_mode],    [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_DEV],     [stat], [st_dev],     [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_UID],     [stat], [st_uid],     [#include <sys/stat.h>])
@@ -154,8 +157,11 @@ then
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_BLOCKS],  [stat], [st_blocks],  [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_INO],     [stat], [st_ino],     [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_ATIME],   [stat], [st_atime],   [#include <sys/stat.h>])
+  FP_COMPUTE_SIZE([SIZEOF_STAT_ST_ATIM_TV_NSEC], [stat], [st_atim.tv_nsec],   [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_MTIME],   [stat], [st_mtime],   [#include <sys/stat.h>])
+  FP_COMPUTE_SIZE([SIZEOF_STAT_ST_MTIM_TV_NSEC],   [stat], [st_mtim.tv_nsec],   [#include <sys/stat.h>])
   FP_COMPUTE_SIZE([SIZEOF_STAT_ST_CTIME],   [stat], [st_ctime],   [#include <sys/stat.h>])
+  FP_COMPUTE_SIZE([SIZEOF_STAT_ST_CTIM_TV_NSEC],   [stat], [st_ctim.tv_nsec],   [#include <sys/stat.h>])
   AC_CHECK_SIZEOF([struct stat], [], [#include <sys/stat.h>])
 
   FP_COMPUTE_OFFSET([OFFSET_UTIMBUF_ACTIME],  [utimbuf], [actime],  [#include <utime.h>])
diff --git a/libraries/base/jsbits/base.js b/libraries/base/jsbits/base.js
index f654432fccdcddf3b8d56a287e574663b305dbd0..9c06cd2702a143074cf302710bfe6765ea1ad95d 100644
--- a/libraries/base/jsbits/base.js
+++ b/libraries/base/jsbits/base.js
@@ -648,13 +648,16 @@ function h$base_fillStat(fs, b, off) {
 
     var atimeS = Math.floor(fs.atimeMs/1000);
     var atimeNs = (fs.atimeMs/1000 - atimeS) * 1000000000;
-    h$base_store_field_number_2(b, off, OFFSET_STAT_ST_ATIME, SIZEOF_STAT_ST_ATIME,  atimeS, atimeNs);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_ATIME, SIZEOF_STAT_ST_ATIME, atimeS);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_ATIM_TV_NSEC, SIZEOF_STAT_ST_ATIM_TV_NSEC, atimeNs);
     var mtimeS = Math.floor(fs.mtimeMs/1000);
     var mtimeNs = (fs.mtimeMs/1000 - mtimeS) * 1000000000;
-    h$base_store_field_number_2(b, off, OFFSET_STAT_ST_MTIME, SIZEOF_STAT_ST_MTIME,  mtimeS, mtimeNs);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_MTIME, SIZEOF_STAT_ST_MTIME, mtimeS);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_MTIM_TV_NSEC, SIZEOF_STAT_ST_MTIM_TV_NSEC, mtimeNs);
     var ctimeS = Math.floor(fs.ctimeMs/1000);
     var ctimeNs = (fs.ctimeMs/1000 - ctimeS) * 1000000000;
-    h$base_store_field_number_2(b, off, OFFSET_STAT_ST_CTIME, SIZEOF_STAT_ST_CTIME,  ctimeS, ctimeNs);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_CTIME, SIZEOF_STAT_ST_CTIME, ctimeS);
+    h$base_store_field_number(b, off, OFFSET_STAT_ST_CTIM_TV_NSEC, SIZEOF_STAT_ST_CTIM_TV_NSEC, ctimeNs);
 }
 #endif
 
@@ -666,28 +669,21 @@ function h$base_store_field_number(ptr, ptr_off, field_off, field_size, val) {
         ptr.i3[(ptr_off>>2)+(field_off>>2)] = val;
     } else if(field_size === 8) {
         h$long_from_number(val, (h,l) => {
-            ptr.i3[(ptr_off>>2)+(field_off>>2)] = h;
-            ptr.i3[(ptr_off>>2)+(field_off>>2)+1] = l;
+            ptr.i3[(ptr_off>>2)+(field_off>>2)] = l;
+            ptr.i3[(ptr_off>>2)+(field_off>>2)+1] = h;
         });
     } else {
         throw new Error("unsupported field size: " + field_size);
     }
 }
 
-function h$base_store_field_number_2(ptr, ptr_off, field_off, field_size, val1, val2) {
-    if(field_size%2) throw new Error("unsupported field size: " + field_size);
-    var half_field_size = field_size>>1;
-    h$base_store_field_number(ptr, ptr_off, field_off, half_field_size, val1);
-    h$base_store_field_number(ptr, ptr_off, field_off+half_field_size, half_field_size, val2);
-}
-
 function h$base_return_field(ptr, ptr_off, field_off, field_size) {
     if(ptr_off%4) throw new Error("ptr not aligned");
     if(field_off%4) throw new Error("field not aligned");
     if(field_size === 4) {
         return ptr.i3[(ptr_off>>2) + (field_off>>2)];
     } else if(field_size === 8) {
-        RETURN_UBX_TUP2(ptr.i3[(ptr_off>>2) + (field_off>>2)], ptr.i3[(ptr_off>>2) + (field_off>>2)+1]);
+        RETURN_UBX_TUP2(ptr.i3[(ptr_off>>2) + (field_off>>2)+1], ptr.i3[(ptr_off>>2) + (field_off>>2)]);
     } else {
         throw new Error("unsupported field size: " + field_size);
     }
diff --git a/testsuite/tests/cabal/all.T b/testsuite/tests/cabal/all.T
index caa3286f792bbef917654dbf4f017a8526aa67c9..a308556faf668184d059f520be59e0abde64be96 100644
--- a/testsuite/tests/cabal/all.T
+++ b/testsuite/tests/cabal/all.T
@@ -54,3 +54,5 @@ test('shadow', [], makefile_test, [])
 test('T12485a', [extra_files(['shadow1.pkg', 'shadow2.pkg', 'shadow3.pkg'])], makefile_test, [])
 
 test('T13703', [extra_files(['test13703a.pkg', 'test13703b.pkg'])], makefile_test, [])
+
+test('fileStatus', normal, compile_and_run, [''])
diff --git a/testsuite/tests/cabal/fileStatus.hs b/testsuite/tests/cabal/fileStatus.hs
new file mode 100644
index 0000000000000000000000000000000000000000..bb5b2b8dd4f6eb999df0ae17d7a21e8998ccc939
--- /dev/null
+++ b/testsuite/tests/cabal/fileStatus.hs
@@ -0,0 +1,110 @@
+{-
+   This is a simple test program for file metadata. It tests a few
+   operations on files and directories, to ensure that our compiler
+   and filesystem produce sensible results.
+
+   If this test fails, it is likely that cabal or backpack tests
+   will fail too.
+
+   Some properties tested:
+
+      * temporary files are regular files and not directories
+      * the current directory is a directory
+      * file size of small temporary files is correct
+      * modification time of created temporary files is close to current time (60s)
+      * modification time of a second temporary file is later than the first
+
+ -}
+{-# LANGUAGE CPP #-}
+
+import Control.Monad (replicateM_)
+
+import Data.Time.Clock
+import System.IO
+import qualified System.Directory as D
+import System.IO.Error
+import Control.Exception
+import Control.Concurrent (threadDelay)
+
+#if !defined(mingw32_HOST_OS)
+import qualified System.Posix.Files as P
+import Data.Time.Clock.POSIX
+#endif
+
+data FileInfo = FileInfo { fiSize          :: Integer
+                         , fiModified      :: UTCTime
+                         , fiIsRegularFile :: Bool
+                         , fiIsDirectory   :: Bool
+                         } deriving (Eq, Show)
+
+testFile1, testFile2 :: FilePath
+testFile1 = "test1.out"
+testFile2 = "test2.out"
+
+main :: IO ()
+main = do
+  putStrLn ("checking file " ++ testFile1)
+  handleFileSize1 <- withBinaryFile testFile1 WriteMode $ \h -> do
+    replicateM_ 50 (hPutChar h 'a')
+    hFileSize h
+  fi1 <- getFileInfo testFile1
+  D.removeFile testFile1
+  putStrLn ("handle file size: " ++ show handleFileSize1)
+  currentTime1 <- getCurrentTime
+  printFileInfo currentTime1 fi1
+
+  putStrLn ("\nchecking current directory")
+  currentDir <- D.getCurrentDirectory
+  di  <- getFileInfo currentDir
+  putStrLn ("is regular file: " ++ show (fiIsRegularFile di))
+  putStrLn ("is directory: " ++ show (fiIsDirectory di))
+
+  -- wait two seconds before testing the second file
+  threadDelay 2000000
+
+  putStrLn ("\nchecking file " ++ testFile2)
+  handleFileSize2 <- withBinaryFile testFile2 WriteMode $ \h -> do
+    replicateM_ 75 (hPutChar h 'b')
+    hFileSize h
+  fi2 <- getFileInfo testFile2
+  D.removeFile testFile2
+  currentTime2 <- getCurrentTime
+  putStrLn ("handle file size: " ++ show handleFileSize2)
+  printFileInfo currentTime2 fi2
+
+  -- check that the second file was modified after the first
+  putStrLn ("second file modified after first: " ++ show (diffUTCTime (fiModified fi2) (fiModified fi1) >= 1))
+
+
+printFileInfo :: UTCTime -> FileInfo -> IO ()
+printFileInfo time fi = do
+  putStrLn $ "file size: " ++ show (fiSize fi)
+  putStrLn $ "is regular file: " ++ show (fiIsRegularFile fi)
+  putStrLn $ "is directory: " ++ show (fiIsDirectory fi)
+  putStrLn $ "time stamp close enough: " ++ show (closeEnough time (fiModified fi))
+
+getFileInfo :: FilePath -> IO FileInfo
+getFileInfo path = do
+  -- get some basic info about the path
+  dirExists  <- D.doesDirectoryExist path
+  fileExists <- D.doesFileExist path
+  fileSize   <- if fileExists then D.getFileSize path else pure 0
+  modTime    <- D.getModificationTime path
+#if !defined(mingw32_HOST_OS)
+  -- check against unix package (which uses a different way to access some fields of the stat structure)
+  fs <- P.getFileStatus path
+  check "isRegularFile" (P.isRegularFile fs == fileExists)
+  check "isDirectory"   (P.isDirectory fs   == dirExists)
+  check "modificationTime" (closeEnough (posixSecondsToUTCTime (realToFrac (P.modificationTime fs))) modTime)
+  check "fileSize"      (fromIntegral (P.fileSize fs) == fileSize || not fileExists)
+#endif
+  pure (FileInfo fileSize modTime fileExists dirExists)
+
+
+check :: String -> Bool -> IO ()
+check err False = throwIO (userError err)
+check _   True  = pure ()
+
+closeEnough :: UTCTime -> UTCTime -> Bool
+closeEnough a b = abs (diffUTCTime a b) < 60
+
diff --git a/testsuite/tests/cabal/fileStatus.stdout b/testsuite/tests/cabal/fileStatus.stdout
new file mode 100644
index 0000000000000000000000000000000000000000..821f787291d4367aa505051b85a352317d69fa34
--- /dev/null
+++ b/testsuite/tests/cabal/fileStatus.stdout
@@ -0,0 +1,18 @@
+checking file test1.out
+handle file size: 50
+file size: 50
+is regular file: True
+is directory: False
+time stamp close enough: True
+
+checking current directory
+is regular file: False
+is directory: True
+
+checking file test2.out
+handle file size: 75
+file size: 75
+is regular file: True
+is directory: False
+time stamp close enough: True
+second file modified after first: True