This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git

commit 304f5fd353e85b7789963bce11fef4229672ead9
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Nov 8 11:55:30 2026 +0100

    testing/fs/fatgap: Add cases for O_APPEND, ftruncate(), statfs() and stat().
    
    Add cases that run on each volume after the write past EOF cases:
    
    - append_seek, append_setfl, append_pwrite, append_twofd: with O_APPEND
      each write() must go to the end of the file, also after a seek to the
      start, after fcntl(F_SETFL), with pwrite() and from two handles that
      write whole sectors in turn.
    - full_volume: write until the volume is full.  The counts that write()
      returns must add up to the offset and to the file size, and the write
      after the short one must fail with ENOSPC.
    - trunc_twofd: after ftruncate() on one handle makes the file longer, a
      second handle must read zeros, in the last sector of the file and on a
      new cluster.
    - free_count: statfs() must give the number of clusters that a file can
      get.  On FAT32 the case first sets the FSINFO free count to unknown, so
      that the file system counts the free clusters in the FAT.
    - stat_open: stat() and fstat() must give the size of an open file after
      a write, before a sync, on a second handle and after a rename.
    - fsinfo (FAT32, on the new volume): the free count in the FSINFO sector
      must be the number of data clusters less the root directory cluster.
    
    Each case reads the file back on a new handle or after a remount where it
    applies, and compares the free clusters after the unlink.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 testing/fs/fatgap/Kconfig       |  16 +-
 testing/fs/fatgap/fatgap_main.c | 736 +++++++++++++++++++++++++++++++++++++++-
 2 files changed, 741 insertions(+), 11 deletions(-)

diff --git a/testing/fs/fatgap/Kconfig b/testing/fs/fatgap/Kconfig
index 9192c291a..690c22f29 100644
--- a/testing/fs/fatgap/Kconfig
+++ b/testing/fs/fatgap/Kconfig
@@ -4,7 +4,7 @@
 #
 
 config TESTING_FATGAP
-       tristate "FAT write past EOF test"
+       tristate "FAT file system test"
        default n
        depends on FS_FAT && FSUTILS_MKFATFS && BOARDCTL_MKRD
        ---help---
@@ -13,6 +13,16 @@ config TESTING_FATGAP
                is on a cluster boundary, one byte below or above it, in the 
middle
                of a cluster, or zero.
 
+               Other cases write with O_APPEND after a seek, after 
fcntl(F_SETFL),
+               with pwrite() and from two handles, and fill the volume to 
check the
+               count of the last, short write.
+
+               More cases check that a second handle reads zeros after 
ftruncate()
+               makes the file longer, that statfs() gives the number of 
clusters
+               that a file can get, that stat() and fstat() give the size of an
+               open file before a sync, and on FAT32 the free cluster count 
that
+               mkfatfs writes in the FSINFO sector.
+
                The test makes its own RAM disks: 512 KiB for FAT12, about 2 
MiB for
                FAT16 and about 34 MiB for FAT32.  It skips a FAT type when the 
memory
                for its RAM disk is not available.  The arguments select the FAT
@@ -28,11 +38,11 @@ config TESTING_FATGAP_PROGNAME
                program is installed.
 
 config TESTING_FATGAP_PRIORITY
-       int "FAT write past EOF test task priority"
+       int "FAT file system test task priority"
        default 100
 
 config TESTING_FATGAP_STACKSIZE
-       int "FAT write past EOF test stack size"
+       int "FAT file system test stack size"
        default DEFAULT_TASK_STACKSIZE
 
 endif
diff --git a/testing/fs/fatgap/fatgap_main.c b/testing/fs/fatgap/fatgap_main.c
index 618c07971..937acde3b 100644
--- a/testing/fs/fatgap/fatgap_main.c
+++ b/testing/fs/fatgap/fatgap_main.c
@@ -29,6 +29,18 @@
  *
  * Each case reads the file back on a new handle and after a remount, and
  * compares the number of free clusters.
+ *
+ * Other cases write with O_APPEND: each write must go to the end of the
+ * file, also after a seek, after fcntl(F_SETFL), with pwrite() and from two
+ * handles.  One case fills the volume: a write that is cut short must
+ * return the number of bytes that it wrote, and the next write must fail
+ * with ENOSPC.
+ *
+ * Other cases check that a second handle reads the zeros after an
+ * ftruncate() makes the file longer, that statfs() gives the number of
+ * clusters that a file can get, and that stat() and fstat() give the size
+ * of an open file before a sync.  On FAT32 a case checks the free cluster
+ * count that mkfatfs writes in the FSINFO sector.
  */
 
 /****************************************************************************
@@ -39,10 +51,13 @@
 
 #include <sys/boardctl.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/statfs.h>
 
+#include <endian.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -63,9 +78,11 @@
 #define FATGAP_DEV       "/dev/ram99"
 #define FATGAP_MNT       "/fatgap"
 #define FATGAP_FILE      FATGAP_MNT "/A.BIN"
+#define FATGAP_FILE2     FATGAP_MNT "/B.BIN"
 #define FATGAP_SECTSIZE  512
 #define FATGAP_FILL      0xa5
 #define FATGAP_SMALLIO   37
+#define FATGAP_FULLIO    3000          /* Not a multiple of a sector */
 #define FATGAP_NITEMS(a) (sizeof(a) / sizeof((a)[0]))
 
 /****************************************************************************
@@ -92,6 +109,12 @@ struct fatgap_case_s
   int len_byte;
 };
 
+struct fatgap_wcase_s
+{
+  FAR const char *name;
+  CODE void (*run)(void);
+};
+
 enum fatgap_mode_e
 {
   MODE_REOPEN,                 /* A new handle writes past EOF */
@@ -100,6 +123,19 @@ enum fatgap_mode_e
   MODE_NUM
 };
 
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void fatgap_append_seek(void);
+static void fatgap_append_setfl(void);
+static void fatgap_append_pwrite(void);
+static void fatgap_append_twofd(void);
+static void fatgap_full_volume(void);
+static void fatgap_trunc_twofd(void);
+static void fatgap_free_count(void);
+static void fatgap_stat_open(void);
+
 /****************************************************************************
  * Private Data
  ****************************************************************************/
@@ -138,6 +174,18 @@ static FAR const char *g_modes[MODE_NUM] =
   "reopen", "samefd", "twofd"
 };
 
+static const struct fatgap_wcase_s g_wcases[] =
+{
+  { "append_seek",   fatgap_append_seek   },
+  { "append_setfl",  fatgap_append_setfl  },
+  { "append_pwrite", fatgap_append_pwrite },
+  { "append_twofd",  fatgap_append_twofd  },
+  { "full_volume",   fatgap_full_volume   },
+  { "trunc_twofd",   fatgap_trunc_twofd   },
+  { "free_count",    fatgap_free_count    },
+  { "stat_open",     fatgap_stat_open     },
+};
+
 static FAR const struct fatgap_vol_s *g_vol;
 static FAR const char *g_case;
 static FAR const char *g_mode;
@@ -310,6 +358,39 @@ static long fatgap_free_clusters(FAR off_t *clustsize)
   return buf.f_bfree;
 }
 
+static void fatgap_count_case(void)
+{
+  if (g_case_fail > 0)
+    {
+      g_fail++;
+    }
+  else
+    {
+      printf("fatgap: FAT%d %s %s PASS\n", g_vol->fattype, g_case, g_mode);
+      g_pass++;
+    }
+}
+
+/* Remove the file, check that all its clusters are free again and count
+ * the case.
+ */
+
+static void fatgap_end_case(long free0)
+{
+  long nfree;
+
+  unlink(FATGAP_FILE);
+  fatgap_remount();
+
+  nfree = fatgap_free_clusters(NULL);
+  if (nfree != free0)
+    {
+      fatgap_fail("%ld free clusters after unlink, want %ld", nfree, free0);
+    }
+
+  fatgap_count_case();
+}
+
 static void fatgap_run_case(FAR const struct fatgap_case_s *c, int mode,
                             off_t clustsize, long free0)
 {
@@ -417,26 +498,344 @@ out:
       close(fd2);
     }
 
-  unlink(FATGAP_FILE);
+  fatgap_end_case(free0);
+}
+
+/* Write a string; a short write is a failure */
+
+static int fatgap_puts(int fd, FAR const char *str)
+{
+  size_t len = strlen(str);
+  ssize_t ret = write(fd, str, len);
+
+  if (ret != len)
+    {
+      fatgap_fail("write \"%s\": ret %zd errno %d", str, ret, errno);
+      return -1;
+    }
+
+  return 0;
+}
+
+/* The file must hold each byte of want, unit times */
+
+static void fatgap_check_units(FAR const char *want, size_t unit,
+                               FAR const char *where)
+{
+  size_t len = strlen(want) * unit;
+  ssize_t ret;
+  size_t i;
+  int fd;
+
+  fd = open(FATGAP_FILE, O_RDONLY);
+  if (fd < 0)
+    {
+      fatgap_fail("%s: open: errno %d", where, errno);
+      return;
+    }
+
+  ret = read(fd, g_buf, sizeof(g_buf));
+  close(fd);
+  if (ret != len)
+    {
+      fatgap_fail("%s: size %zd, want %zu", where, ret, len);
+      return;
+    }
+
+  for (i = 0; i < len; i++)
+    {
+      if (g_buf[i] != want[i / unit])
+        {
+          fatgap_fail("%s: byte %zu is 0x%02x, want 0x%02x", where, i,
+                      g_buf[i], want[i / unit]);
+          return;
+        }
+    }
+}
+
+static void fatgap_check_append(FAR const char *want, size_t unit)
+{
+  fatgap_check_units(want, unit, "new handle");
   fatgap_remount();
+  fatgap_check_units(want, unit, "after remount");
+}
 
-  nfree = fatgap_free_clusters(NULL);
-  if (nfree != free0)
+/* O_APPEND: a write after a seek to the start goes to the end */
+
+static void fatgap_append_seek(void)
+{
+  off_t off;
+  int fd;
+
+  fd = open(FATGAP_FILE, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
+  if (fd < 0)
     {
-      fatgap_fail("%ld free clusters after unlink, want %ld", nfree, free0);
+      fatgap_fail("create: errno %d", errno);
+      return;
     }
 
-  if (g_case_fail > 0)
+  if (fatgap_puts(fd, "0123456789") == 0 && lseek(fd, 0, SEEK_SET) == 0 &&
+      fatgap_puts(fd, "AB") == 0)
     {
-      g_fail++;
+      off = lseek(fd, 0, SEEK_CUR);
+      if (off != 12)
+        {
+          fatgap_fail("offset after the write %" PRIdOFF ", want 12", off);
+        }
+    }
+
+  close(fd);
+  fatgap_check_append("0123456789AB", 1);
+}
+
+/* O_APPEND set with fcntl(F_SETFL) on an open handle */
+
+static void fatgap_append_setfl(void)
+{
+  int flags;
+  int fd;
+
+  fd = open(FATGAP_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  if (fatgap_puts(fd, "0123456789") == 0)
+    {
+      flags = fcntl(fd, F_GETFL);
+      if (flags < 0 || fcntl(fd, F_SETFL, flags | O_APPEND) < 0)
+        {
+          fatgap_fail("fcntl: errno %d", errno);
+        }
+      else if (lseek(fd, 0, SEEK_SET) == 0)
+        {
+          fatgap_puts(fd, "Z");
+        }
+    }
+
+  close(fd);
+  fatgap_check_append("0123456789Z", 1);
+}
+
+/* pwrite() on a handle with O_APPEND appends, as on Linux */
+
+static void fatgap_append_pwrite(void)
+{
+  ssize_t ret;
+  int fd;
+
+  fd = open(FATGAP_FILE, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  if (fatgap_puts(fd, "0123456789") == 0)
+    {
+      ret = pwrite(fd, "P", 1, 2);
+      if (ret != 1)
+        {
+          fatgap_fail("pwrite: ret %zd errno %d", ret, errno);
+        }
+    }
+
+  close(fd);
+  fatgap_check_append("0123456789P", 1);
+}
+
+/* Two handles with O_APPEND write whole sectors in turn */
+
+static void fatgap_append_twofd(void)
+{
+  ssize_t ret;
+  int fd[2];
+  int i;
+
+  fd[0] = open(FATGAP_FILE, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0666);
+  fd[1] = open(FATGAP_FILE, O_WRONLY | O_APPEND);
+  if (fd[0] < 0 || fd[1] < 0)
+    {
+      fatgap_fail("open: errno %d", errno);
     }
   else
     {
-      printf("fatgap: FAT%d %s %s PASS\n", g_vol->fattype, g_case, g_mode);
-      g_pass++;
+      for (i = 0; i < 3; i++)
+        {
+          memset(g_buf, "abc"[i], FATGAP_SECTSIZE);
+          ret = write(fd[i & 1], g_buf, FATGAP_SECTSIZE);
+          if (ret != FATGAP_SECTSIZE)
+            {
+              fatgap_fail("write %d: ret %zd errno %d", i, ret, errno);
+              break;
+            }
+        }
+    }
+
+  for (i = 0; i < 2; i++)
+    {
+      if (fd[i] >= 0)
+        {
+          close(fd[i]);
+        }
+    }
+
+  fatgap_check_append("abc", FATGAP_SECTSIZE);
+}
+
+/* Fill the volume.  The counts that write() returns must add up to the
+ * offset and to the size of the file.
+ */
+
+static void fatgap_full_volume(void)
+{
+  off_t maxbytes = g_vol->nsectors * FATGAP_SECTSIZE;
+  struct stat st;
+  off_t total = 0;
+  off_t off;
+  ssize_t ret = 0;
+  int err = 0;
+  int fd;
+
+  fd = open(FATGAP_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  memset(g_buf, FATGAP_FILL, FATGAP_FULLIO);
+  while (total <= maxbytes)
+    {
+      ret = write(fd, g_buf, FATGAP_FULLIO);
+      if (ret <= 0)
+        {
+          err = errno;
+          break;
+        }
+
+      total += ret;
+    }
+
+  if (ret >= 0 || err != ENOSPC)
+    {
+      fatgap_fail("last write: ret %zd errno %d, want -1 errno %d", ret,
+                  err, ENOSPC);
+    }
+
+  printf("fatgap: FAT%d %s: %" PRIdOFF " bytes written\n", g_vol->fattype,
+         g_case, total);
+
+  off = lseek(fd, 0, SEEK_CUR);
+  if (off != total)
+    {
+      fatgap_fail("offset %" PRIdOFF ", the counts add up to %" PRIdOFF, off,
+                  total);
+    }
+
+  close(fd);
+
+  if (stat(FATGAP_FILE, &st) < 0)
+    {
+      fatgap_fail("stat: errno %d", errno);
+    }
+  else if (st.st_size != total)
+    {
+      fatgap_fail("size %" PRIdOFF ", the counts add up to %" PRIdOFF,
+                  st.st_size, total);
+    }
+}
+
+/* A second handle must read zeros after ftruncate() on the first handle
+ * makes the file longer: in the last sector of the file and on a new
+ * cluster.
+ */
+
+static void fatgap_trunc_twofd(void)
+{
+  off_t clustsize;
+  int fd;
+  int fd2 = -1;
+
+  if (fatgap_free_clusters(&clustsize) < 0)
+    {
+      return;
+    }
+
+  fd = open(FATGAP_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  if (fatgap_write(fd, 0, 2 * clustsize, 1, sizeof(g_buf)) < 0)
+    {
+      goto out;
+    }
+
+  fd2 = open(FATGAP_FILE, O_RDONLY);
+  if (fd2 < 0)
+    {
+      fatgap_fail("open second handle: errno %d", errno);
+      goto out;
+    }
+
+  if (ftruncate(fd, 100) < 0 || ftruncate(fd, 400) < 0)
+    {
+      fatgap_fail("ftruncate to 100, then 400: errno %d", errno);
+      goto out;
+    }
+
+  fatgap_check(fd2, 0, 100, 1, "second handle", "old data");
+  fatgap_check(fd2, 100, 300, -1, "second handle", "zeros in the sector");
+
+  if (ftruncate(fd, clustsize + 100) < 0)
+    {
+      fatgap_fail("ftruncate to %" PRIdOFF ": errno %d", clustsize + 100,
+                  errno);
+      goto out;
+    }
+
+  fatgap_check(fd2, 100, clustsize, -1, "second handle",
+               "zeros on a new cluster");
+
+  close(fd);
+  fd = -1;
+
+  fatgap_check_fd(fd2, 100, clustsize + 100, 0, "second handle");
+  close(fd2);
+  fd2 = -1;
+
+  fatgap_check_new_fd(100, clustsize + 100, 0, "new handle");
+  fatgap_remount();
+  fatgap_check_new_fd(100, clustsize + 100, 0, "after remount");
+
+out:
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+
+  if (fd2 >= 0)
+    {
+      close(fd2);
     }
 }
 
+static void fatgap_run_wcase(FAR const struct fatgap_wcase_s *c,
+                             long free0)
+{
+  g_case = c->name;
+  g_mode = "write";
+  g_case_fail = 0;
+
+  c->run();
+  fatgap_end_case(free0);
+}
+
 /* Write the fill byte to the whole RAM disk */
 
 static int fatgap_fill(void)
@@ -469,6 +868,317 @@ static int fatgap_fill(void)
   return 0;
 }
 
+static uint32_t fatgap_get32(FAR const uint8_t *p)
+{
+  uint32_t v;
+
+  memcpy(&v, p, sizeof(v));
+  return le32toh(v);
+}
+
+/* FAT32: the free count in the FSINFO sector of a new volume is the number
+ * of data clusters less the root directory cluster.
+ */
+
+static void fatgap_check_fsinfo(void)
+{
+  FAR const uint8_t *fsi = &g_buf[FATGAP_SECTSIZE];
+  uint32_t nclusters;
+  uint32_t nfree;
+  off_t sector;
+  int fd;
+
+  g_case = "fsinfo";
+  g_mode = "-";
+  g_case_fail = 0;
+
+  fd = open(FATGAP_DEV, O_RDONLY);
+  if (fd < 0 || pread(fd, g_buf, FATGAP_SECTSIZE, 0) != FATGAP_SECTSIZE)
+    {
+      fatgap_fail("read the boot sector: errno %d", errno);
+      goto out;
+    }
+
+  /* FSInfo at 48, TotSec32 at 32, RsvdSecCnt at 14, NumFATs at 16,
+   * FATSz32 at 36, SecPerClus at 13.
+   */
+
+  sector = g_buf[48] | (g_buf[49] << 8);
+  nclusters = (fatgap_get32(&g_buf[32]) - (g_buf[14] | (g_buf[15] << 8)) -
+               g_buf[16] * fatgap_get32(&g_buf[36])) / g_buf[13];
+
+  if (pread(fd, &g_buf[FATGAP_SECTSIZE], FATGAP_SECTSIZE,
+            sector * FATGAP_SECTSIZE) != FATGAP_SECTSIZE)
+    {
+      fatgap_fail("read the FSINFO sector %" PRIdOFF ": errno %d", sector,
+                  errno);
+      goto out;
+    }
+
+  if (fatgap_get32(fsi) != 0x41615252 ||
+      fatgap_get32(&fsi[484]) != 0x61417272)
+    {
+      fatgap_fail("no FSINFO signature in sector %" PRIdOFF, sector);
+      goto out;
+    }
+
+  nfree = fatgap_get32(&fsi[488]);
+  if (nfree != nclusters - 1)
+    {
+      fatgap_fail("free count %" PRIu32 ", want %" PRIu32 " (%" PRIu32
+                  " clusters, one for the root directory)", nfree,
+                  nclusters - 1, nclusters);
+    }
+
+out:
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+
+  fatgap_count_case();
+}
+
+/* FAT32: set the free count in the FSINFO sector to unknown (0xffffffff),
+ * so that the file system counts the free clusters in the FAT.
+ */
+
+static int fatgap_fsinfo_unknown(void)
+{
+  off_t sector;
+  int ret = -1;
+  int fd;
+
+  if (umount(FATGAP_MNT) < 0)
+    {
+      fatgap_fail("umount: errno %d", errno);
+      return -1;
+    }
+
+  fd = open(FATGAP_DEV, O_RDWR);
+  if (fd < 0 || pread(fd, g_buf, FATGAP_SECTSIZE, 0) != FATGAP_SECTSIZE)
+    {
+      fatgap_fail("read the boot sector: errno %d", errno);
+      goto out;
+    }
+
+  /* BPB_FSInfo: the sector number of FSINFO */
+
+  sector = g_buf[48] | (g_buf[49] << 8);
+  if (pread(fd, g_buf, FATGAP_SECTSIZE, sector * FATGAP_SECTSIZE) !=
+      FATGAP_SECTSIZE)
+    {
+      fatgap_fail("read the FSINFO sector: errno %d", errno);
+      goto out;
+    }
+
+  /* FSI_Free_Count at 488 */
+
+  memset(&g_buf[488], 0xff, 4);
+  if (pwrite(fd, g_buf, FATGAP_SECTSIZE, sector * FATGAP_SECTSIZE) !=
+      FATGAP_SECTSIZE)
+    {
+      fatgap_fail("write the FSINFO sector: errno %d", errno);
+      goto out;
+    }
+
+  ret = 0;
+
+out:
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+
+  if (mount(FATGAP_DEV, FATGAP_MNT, "vfat", 0, NULL) < 0)
+    {
+      fatgap_fail("mount: errno %d", errno);
+      ret = -1;
+    }
+
+  return ret;
+}
+
+/* statfs() must give the number of clusters that a file can get.  On
+ * FAT32 the file system must count them in the FAT, not take the count of
+ * the FSINFO sector.
+ */
+
+static void fatgap_free_count(void)
+{
+  off_t clustsize;
+  long before;
+  long nclust = 0;
+  long nfree;
+  ssize_t ret;
+  int fd;
+
+  if (g_vol->fattype == 32 && fatgap_fsinfo_unknown() < 0)
+    {
+      return;
+    }
+
+  before = fatgap_free_clusters(&clustsize);
+  if (before < 0)
+    {
+      return;
+    }
+
+  /* Fill the volume with whole clusters */
+
+  fd = open(FATGAP_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  memset(g_buf, FATGAP_FILL, clustsize);
+  while ((ret = write(fd, g_buf, clustsize)) == clustsize)
+    {
+      nclust++;
+    }
+
+  if (ret != -1 || errno != ENOSPC)
+    {
+      fatgap_fail("write of cluster %ld: ret %zd errno %d", nclust, ret,
+                  errno);
+    }
+
+  if (before != nclust)
+    {
+      fatgap_fail("%ld free clusters, a file gets %ld", before, nclust);
+    }
+
+  nfree = fatgap_free_clusters(NULL);
+  if (nfree != 0)
+    {
+      fatgap_fail("%ld free clusters on a full volume", nfree);
+    }
+
+  close(fd);
+}
+
+/* stat() of path and fstat() of fd must give the size want */
+
+static void fatgap_check_size(FAR const char *where, FAR const char *path,
+                              int fd, off_t want)
+{
+  struct stat buf;
+
+  if (stat(path, &buf) < 0)
+    {
+      fatgap_fail("%s: stat: errno %d", where, errno);
+    }
+  else if (buf.st_size != want)
+    {
+      fatgap_fail("%s: stat: size %" PRIdOFF ", want %" PRIdOFF, where,
+                  buf.st_size, want);
+    }
+
+  if (fd < 0)
+    {
+      return;
+    }
+
+  if (fstat(fd, &buf) < 0)
+    {
+      fatgap_fail("%s: fstat: errno %d", where, errno);
+    }
+  else if (buf.st_size != want)
+    {
+      fatgap_fail("%s: fstat: size %" PRIdOFF ", want %" PRIdOFF, where,
+                  buf.st_size, want);
+    }
+}
+
+/* stat() and fstat() must give the size of an open file at once after a
+ * write, before a sync, and after a rename of the open file.
+ */
+
+static void fatgap_stat_open(void)
+{
+  struct stat buf;
+  int fd;
+  int fd2 = -1;
+
+  fd = open(FATGAP_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666);
+  if (fd < 0)
+    {
+      fatgap_fail("create: errno %d", errno);
+      return;
+    }
+
+  if (fatgap_write(fd, 0, 1000, 1, sizeof(g_buf)) < 0)
+    {
+      goto out;
+    }
+
+  fatgap_check_size("new file", FATGAP_FILE, fd, 1000);
+
+  if (fatgap_write(fd, 1000, 500, 1, sizeof(g_buf)) < 0)
+    {
+      goto out;
+    }
+
+  fatgap_check_size("longer file", FATGAP_FILE, fd, 1500);
+
+  fd2 = open(FATGAP_FILE, O_RDONLY);
+  if (fd2 < 0)
+    {
+      fatgap_fail("open second handle: errno %d", errno);
+      goto out;
+    }
+
+  fatgap_check_size("second handle", FATGAP_FILE, fd2, 1500);
+
+  if (fsync(fd) < 0)
+    {
+      fatgap_fail("fsync: errno %d", errno);
+    }
+
+  fatgap_check_size("after fsync", FATGAP_FILE, fd, 1500);
+
+  if (rename(FATGAP_FILE, FATGAP_FILE2) < 0)
+    {
+      fatgap_fail("rename: errno %d", errno);
+      goto out;
+    }
+
+  if (fatgap_write(fd, 1500, 100, 1, sizeof(g_buf)) < 0)
+    {
+      goto out;
+    }
+
+  fatgap_check_size("after rename", FATGAP_FILE2, fd, 1600);
+  if (stat(FATGAP_FILE, &buf) == 0 || errno != ENOENT)
+    {
+      fatgap_fail("after rename: stat of the old name: errno %d", errno);
+    }
+
+  close(fd);
+  fd = -1;
+  close(fd2);
+  fd2 = -1;
+
+  fatgap_check_size("after close", FATGAP_FILE2, -1, 1600);
+  fatgap_remount();
+  fatgap_check_size("after remount", FATGAP_FILE2, -1, 1600);
+
+out:
+  if (fd >= 0)
+    {
+      close(fd);
+    }
+
+  if (fd2 >= 0)
+    {
+      close(fd2);
+    }
+
+  unlink(FATGAP_FILE2);
+}
+
 static void fatgap_run_volume(void)
 {
   struct boardioc_mkrd_s desc;
@@ -526,6 +1236,11 @@ static void fatgap_run_volume(void)
   printf("fatgap: FAT%d %ld byte clusters, %ld free\n", g_vol->fattype,
          (long)clustsize, free0);
 
+  if (g_vol->fattype == 32)
+    {
+      fatgap_check_fsinfo();
+    }
+
   for (m = 0; m < MODE_NUM; m++)
     {
       for (c = 0; c < FATGAP_NITEMS(g_cases); c++)
@@ -534,6 +1249,11 @@ static void fatgap_run_volume(void)
         }
     }
 
+  for (c = 0; c < FATGAP_NITEMS(g_wcases); c++)
+    {
+      fatgap_run_wcase(&g_wcases[c], free0);
+    }
+
 out:
   umount(FATGAP_MNT);
   unlink(FATGAP_DEV);

Reply via email to