NEWS.stable: log cherry-pick [e446f25]->[c092018] relocatable-shell: Update suggested...
[gnulib.git] / tests / test-rename.h
index a43300d..2bc610f 100644 (file)
@@ -1,5 +1,5 @@
 /* Test of rename() function.
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009-2014 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    appropriate headers are already included.  If PRINT, warn before
    skipping symlink tests with status 77.  */
 
+/* Tests whether a file, given by a file name without slashes, exists in
+   the current directory, by scanning the directory entries.  */
+static bool
+dentry_exists (const char *filename)
+{
+  bool exists = false;
+  DIR *dir = opendir (".");
+
+  ASSERT (dir != NULL);
+  for (;;)
+    {
+      struct dirent *d = readdir (dir);
+      if (d == NULL)
+        break;
+      if (strcmp (d->d_name, filename) == 0)
+        {
+          exists = true;
+          break;
+        }
+    }
+  ASSERT (closedir (dir) == 0);
+  return exists;
+}
+
+/* Asserts that a specific file, given by a file name without slashes, does
+   not exist in the current directory.  */
+static void
+assert_nonexistent (const char *filename)
+{
+  struct stat st;
+
+  /* The usual way to test the presence of a file is via stat() or lstat().  */
+  errno = 0;
+  if (stat (filename, &st) == -1)
+    ASSERT (errno == ENOENT);
+  else
+    {
+      /* But after renaming a directory over an empty directory on an NFS-
+         mounted file system, on Linux 2.6.18, for a period of 30 seconds the
+         old directory name is "present" according to stat() but "nonexistent"
+         according to dentry_exists().  */
+      ASSERT (!dentry_exists (filename));
+      /* Remove the old directory name, so that subsequent mkdir calls
+         succeed.  */
+      (void) rmdir (filename);
+    }
+}
+
 static int
 test_rename (int (*func) (char const *, char const *), bool print)
 {
@@ -31,168 +79,400 @@ test_rename (int (*func) (char const *, char const *), bool print)
   ASSERT (close (fd) == 0);
   ASSERT (mkdir (BASE "dir", 0700) == 0);
 
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
+
   /* Obvious errors.  */
 
-  errno = 0; /* Missing source.  */
-  ASSERT (func (BASE "missing", BASE "missing") == -1);
-  ASSERT (errno == ENOENT);
-  errno = 0;
-  ASSERT (func (BASE "missing/", BASE "missing") == -1);
-  ASSERT (errno == ENOENT);
-  errno = 0;
-  ASSERT (func (BASE "missing", BASE "missing/") == -1);
-  ASSERT (errno == ENOENT);
-  errno = 0; /* Empty operand.  */
-  ASSERT (func ("", BASE "missing") == -1);
-  ASSERT (errno == ENOENT);
-  errno = 0;
-  ASSERT (func (BASE "file", "") == -1);
-  ASSERT (errno == ENOENT);
-  errno = 0;
-  ASSERT (func (BASE "", "") == -1);
-  ASSERT (errno == ENOENT);
+  { /* Missing source.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "missing", BASE "missing") == -1);
+      ASSERT (errno == ENOENT);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "missing/", BASE "missing") == -1);
+      ASSERT (errno == ENOENT);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "missing", BASE "missing/") == -1);
+      ASSERT (errno == ENOENT);
+    }
+  }
+  { /* Empty operand.  */
+    {
+      errno = 0;
+      ASSERT (func ("", BASE "missing") == -1);
+      ASSERT (errno == ENOENT);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "file", "") == -1);
+      ASSERT (errno == ENOENT);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "", "") == -1);
+      ASSERT (errno == ENOENT);
+    }
+  }
 
   /* Files.  */
-  errno = 0; /* Trailing slash.  */
-  ASSERT (func (BASE "file", BASE "file2/") == -1);
-  ASSERT (errno == ENOENT || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "file/", BASE "file2") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (stat (BASE "file2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (func (BASE "file", BASE "file2") == 0); /* Simple rename.  */
-  errno = 0;
-  ASSERT (stat (BASE "file", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "file2", &st) == 0);
-  ASSERT (st.st_size == 2);
-  ASSERT (close (creat (BASE "file", 0600)) == 0); /* Overwrite.  */
-  errno = 0;
-  ASSERT (func (BASE "file2", BASE "file/") == -1);
-  ASSERT (errno == ENOTDIR);
-  ASSERT (func (BASE "file2", BASE "file") == 0);
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "file", &st) == 0);
-  ASSERT (st.st_size == 2);
-  errno = 0;
-  ASSERT (stat (BASE "file2", &st) == -1);
-  ASSERT (errno == ENOENT);
+
+  { /* Trailing slash.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "file", BASE "file2/") == -1);
+      ASSERT (errno == ENOENT || errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "file/", BASE "file2") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (stat (BASE "file2", &st) == -1);
+      ASSERT (errno == ENOENT);
+    }
+  }
+  { /* Simple rename.  */
+    ASSERT (func (BASE "file", BASE "file2") == 0);
+    errno = 0;
+    ASSERT (stat (BASE "file", &st) == -1);
+    ASSERT (errno == ENOENT);
+    memset (&st, 0, sizeof st);
+    ASSERT (stat (BASE "file2", &st) == 0);
+    ASSERT (st.st_size == 2);
+  }
+  /* Files present here:
+       {BASE}file2
+       {BASE}dir/
+   */
+  { /* Overwrite.  */
+    ASSERT (close (creat (BASE "file", 0600)) == 0);
+    errno = 0;
+    ASSERT (func (BASE "file2", BASE "file/") == -1);
+    ASSERT (errno == ENOTDIR);
+    ASSERT (func (BASE "file2", BASE "file") == 0);
+    memset (&st, 0, sizeof st);
+    ASSERT (stat (BASE "file", &st) == 0);
+    ASSERT (st.st_size == 2);
+    errno = 0;
+    ASSERT (stat (BASE "file2", &st) == -1);
+    ASSERT (errno == ENOENT);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
 
   /* Directories.  */
-  ASSERT (func (BASE "dir", BASE "dir2/") == 0); /* Simple rename.  */
-  errno = 0;
-  ASSERT (stat (BASE "dir", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (stat (BASE "dir2", &st) == 0);
-  ASSERT (func (BASE "dir2/", BASE "dir") == 0);
-  ASSERT (stat (BASE "dir", &st) == 0);
-  errno = 0;
-  ASSERT (stat (BASE "dir2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (func (BASE "dir", BASE "dir2") == 0);
-  errno = 0;
-  ASSERT (stat (BASE "dir", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (stat (BASE "dir2", &st) == 0);
-  ASSERT (mkdir (BASE "dir", 0700) == 0); /* Empty onto empty.  */
-  ASSERT (func (BASE "dir2", BASE "dir") == 0);
-  ASSERT (mkdir (BASE "dir2", 0700) == 0);
-  ASSERT (func (BASE "dir2", BASE "dir/") == 0);
-  ASSERT (mkdir (BASE "dir2", 0700) == 0);
-  ASSERT (func (BASE "dir2/", BASE "dir") == 0);
-  ASSERT (mkdir (BASE "dir2", 0700) == 0);
-  ASSERT (close (creat (BASE "dir/file", 0600)) == 0); /* Empty onto full.  */
-  errno = 0;
-  ASSERT (func (BASE "dir2", BASE "dir") == -1);
-  ASSERT (errno == EEXIST || errno == ENOTEMPTY);
-  errno = 0;
-  ASSERT (func (BASE "dir2/", BASE "dir") == -1);
-  ASSERT (errno == EEXIST || errno == ENOTEMPTY);
-  errno = 0;
-  ASSERT (func (BASE "dir2", BASE "dir/") == -1);
-  ASSERT (errno == EEXIST || errno == ENOTEMPTY);
-  ASSERT (func (BASE "dir", BASE "dir2") == 0); /* Full onto empty.  */
-  errno = 0;
-  ASSERT (stat (BASE "dir", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (stat (BASE "dir2/file", &st) == 0);
-  ASSERT (mkdir (BASE "dir", 0700) == 0);
-  ASSERT (func (BASE "dir2/", BASE "dir") == 0);
-  ASSERT (stat (BASE "dir/file", &st) == 0);
-  errno = 0;
-  ASSERT (stat (BASE "dir2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (mkdir (BASE "dir2", 0700) == 0);
-  ASSERT (func (BASE "dir", BASE "dir2/") == 0);
-  errno = 0;
-  ASSERT (stat (BASE "dir", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (stat (BASE "dir2/file", &st) == 0);
-  ASSERT (unlink (BASE "dir2/file") == 0);
-  errno = 0; /* Reject trailing dot.  */
-  ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
-  ASSERT (errno == EINVAL || errno == ENOENT);
-  ASSERT (mkdir (BASE "dir", 0700) == 0);
-  errno = 0;
-  ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
-  ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
-          || errno == ENOTEMPTY);
-  errno = 0;
-  ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
-  ASSERT (errno == EINVAL || errno == EBUSY);
-  ASSERT (rmdir (BASE "dir") == 0);
-  errno = 0;
-  ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
-  ASSERT (errno == EINVAL || errno == ENOENT);
-  ASSERT (mkdir (BASE "dir", 0700) == 0);
-  errno = 0;
-  ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
-  ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
-          || errno == ENOTEMPTY);
-  errno = 0;
-  ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
-  ASSERT (errno == EINVAL || errno == EBUSY);
-  ASSERT (rmdir (BASE "dir2") == 0);
-  errno = 0; /* Move into subdir.  */
-  ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
-  ASSERT (errno == EINVAL || errno == EACCES);
-  errno = 0;
-  ASSERT (stat (BASE "dir/sub", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
-  errno = 0;
-  ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
-  ASSERT (errno == EINVAL);
-  ASSERT (stat (BASE "dir/sub", &st) == 0);
-  ASSERT (rmdir (BASE "dir/sub") == 0);
+
+  { /* Simple rename.  */
+    {
+      ASSERT (func (BASE "dir", BASE "dir2/") == 0);
+      errno = 0;
+      ASSERT (stat (BASE "dir", &st) == -1);
+      ASSERT (errno == ENOENT);
+      ASSERT (stat (BASE "dir2", &st) == 0);
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}dir2/
+     */
+    {
+      ASSERT (func (BASE "dir2/", BASE "dir") == 0);
+      ASSERT (stat (BASE "dir", &st) == 0);
+      errno = 0;
+      ASSERT (stat (BASE "dir2", &st) == -1);
+      ASSERT (errno == ENOENT);
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "dir", BASE "dir2") == 0);
+      errno = 0;
+      ASSERT (stat (BASE "dir", &st) == -1);
+      ASSERT (errno == ENOENT);
+      ASSERT (stat (BASE "dir2", &st) == 0);
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}dir2/
+     */
+    { /* Empty onto empty.  */
+      ASSERT (mkdir (BASE "dir", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+       */
+      ASSERT (func (BASE "dir2", BASE "dir") == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+       */
+      ASSERT (mkdir (BASE "dir2", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+       */
+      ASSERT (func (BASE "dir2", BASE "dir/") == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+       */
+      ASSERT (mkdir (BASE "dir2", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+       */
+      ASSERT (func (BASE "dir2/", BASE "dir") == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+       */
+      ASSERT (mkdir (BASE "dir2", 0700) == 0);
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}dir/
+         {BASE}dir2/
+     */
+    { /* Empty onto full.  */
+      ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir/file
+           {BASE}dir2/
+       */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir") == -1);
+        ASSERT (errno == EEXIST || errno == ENOTEMPTY);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2/", BASE "dir") == -1);
+        ASSERT (errno == EEXIST || errno == ENOTEMPTY);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir/") == -1);
+        ASSERT (errno == EEXIST || errno == ENOTEMPTY);
+      }
+    }
+    { /* Full onto empty.  */
+      ASSERT (func (BASE "dir", BASE "dir2") == 0);
+      assert_nonexistent (BASE "dir");
+      ASSERT (stat (BASE "dir2/file", &st) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir2/
+           {BASE}dir2/file
+       */
+      ASSERT (mkdir (BASE "dir", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+           {BASE}dir2/file
+       */
+      {
+        ASSERT (func (BASE "dir2/", BASE "dir") == 0);
+        ASSERT (stat (BASE "dir/file", &st) == 0);
+        errno = 0;
+        ASSERT (stat (BASE "dir2", &st) == -1);
+        ASSERT (errno == ENOENT);
+      }
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir/file
+       */
+      ASSERT (mkdir (BASE "dir2", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir/file
+           {BASE}dir2/
+       */
+      {
+        ASSERT (func (BASE "dir", BASE "dir2/") == 0);
+        assert_nonexistent (BASE "dir");
+        ASSERT (stat (BASE "dir2/file", &st) == 0);
+      }
+      /* Files present here:
+           {BASE}file
+           {BASE}dir2/
+           {BASE}dir2/file
+       */
+      ASSERT (unlink (BASE "dir2/file") == 0);
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}dir2/
+     */
+    { /* Reject trailing dot.  */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
+        ASSERT (errno == EINVAL || errno == ENOENT);
+      }
+      ASSERT (mkdir (BASE "dir", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+       */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
+        ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
+                || errno == ENOTEMPTY || errno == EEXIST);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
+        ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST);
+      }
+      ASSERT (rmdir (BASE "dir") == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir2/
+       */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
+        ASSERT (errno == EINVAL || errno == ENOENT);
+      }
+      ASSERT (mkdir (BASE "dir", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir2/
+       */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
+        ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
+                || errno == ENOTEMPTY || errno == EEXIST);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
+        ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST);
+      }
+      ASSERT (rmdir (BASE "dir2") == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+       */
+    }
+    { /* Move into subdir.  */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
+        ASSERT (errno == EINVAL || errno == EACCES);
+      }
+      {
+        errno = 0;
+        ASSERT (stat (BASE "dir/sub", &st) == -1);
+        ASSERT (errno == ENOENT);
+      }
+      ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
+      /* Files present here:
+           {BASE}file
+           {BASE}dir/
+           {BASE}dir/sub/
+       */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
+        ASSERT (errno == EINVAL);
+        ASSERT (stat (BASE "dir/sub", &st) == 0);
+      }
+      ASSERT (rmdir (BASE "dir/sub") == 0);
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
 
   /* Mixing file and directory.  */
-  errno = 0; /* File onto dir.  */
-  ASSERT (func (BASE "file", BASE "dir") == -1);
-  ASSERT (errno == EISDIR || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "file", BASE "dir/") == -1);
-  ASSERT (errno == EISDIR || errno == ENOTDIR);
-  errno = 0; /* Dir onto file.  */
-  ASSERT (func (BASE "dir", BASE "file") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "dir/", BASE "file") == -1);
-  ASSERT (errno == ENOTDIR);
+
+  {
+    { /* File onto dir.  */
+      {
+        errno = 0;
+        ASSERT (func (BASE "file", BASE "dir") == -1);
+        ASSERT (errno == EISDIR || errno == ENOTDIR);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "file", BASE "dir/") == -1);
+        ASSERT (errno == EISDIR || errno == ENOTDIR);
+      }
+    }
+    { /* Dir onto file.  */
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir", BASE "file") == -1);
+        ASSERT (errno == ENOTDIR);
+      }
+      {
+        errno = 0;
+        ASSERT (func (BASE "dir/", BASE "file") == -1);
+        ASSERT (errno == ENOTDIR);
+      }
+    }
+  }
 
   /* Hard links.  */
-  ASSERT (func (BASE "file", BASE "file") == 0); /* File onto self.  */
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "file", &st) == 0);
-  ASSERT (st.st_size == 2);
-  ASSERT (func (BASE "dir", BASE "dir") == 0); /* Empty dir onto self.  */
-  ASSERT (stat (BASE "dir", &st) == 0);
+
+  { /* File onto self.  */
+    ASSERT (func (BASE "file", BASE "file") == 0);
+    memset (&st, 0, sizeof st);
+    ASSERT (stat (BASE "file", &st) == 0);
+    ASSERT (st.st_size == 2);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
+  { /* Empty dir onto self.  */
+    ASSERT (func (BASE "dir", BASE "dir") == 0);
+    ASSERT (stat (BASE "dir", &st) == 0);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
   ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
-  ASSERT (func (BASE "dir", BASE "dir") == 0); /* Full dir onto self.  */
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+       {BASE}dir/file
+   */
+  { /* Full dir onto self.  */
+    ASSERT (func (BASE "dir", BASE "dir") == 0);
+  }
   ASSERT (unlink (BASE "dir/file") == 0);
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
   {
     /*  Not all file systems support link.  Mingw doesn't have
         reliable st_nlink on hard links, but our implementation does
@@ -234,16 +514,33 @@ test_rename (int (*func) (char const *, char const *), bool print)
       }
     ASSERT (ret == 0);
   }
-  ASSERT (func (BASE "file", BASE "file2") == 0); /* File onto hard link.  */
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "file", &st) == 0);
-  ASSERT (st.st_size == 2);
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "file2", &st) == 0);
-  ASSERT (st.st_size == 2);
+  /* Files present here:
+       {BASE}file
+       {BASE}file2       (hard link to file)
+       {BASE}dir/
+   */
+  { /* File onto hard link.  */
+    ASSERT (func (BASE "file", BASE "file2") == 0);
+    memset (&st, 0, sizeof st);
+    ASSERT (stat (BASE "file", &st) == 0);
+    ASSERT (st.st_size == 2);
+    memset (&st, 0, sizeof st);
+    ASSERT (stat (BASE "file2", &st) == 0);
+    ASSERT (st.st_size == 2);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}file2
+       {BASE}dir/
+   */
   ASSERT (unlink (BASE "file2") == 0);
+  /* Files present here:
+       {BASE}file
+       {BASE}dir/
+   */
 
   /* Symlinks.  */
+
   if (symlink (BASE "file", BASE "link1"))
     {
       if (print)
@@ -253,118 +550,298 @@ test_rename (int (*func) (char const *, char const *), bool print)
       ASSERT (rmdir (BASE "dir") == 0);
       return 77;
     }
-  ASSERT (func (BASE "link1", BASE "link2") == 0); /* Simple rename.  */
-  ASSERT (stat (BASE "file", &st) == 0);
-  errno = 0;
-  ASSERT (lstat (BASE "link1", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link2", &st) == 0);
-  ASSERT (S_ISLNK (st.st_mode));
-  ASSERT (symlink (BASE "nowhere", BASE "link1") == 0); /* Overwrite.  */
-  ASSERT (func (BASE "link2", BASE "link1") == 0);
-  memset (&st, 0, sizeof st);
-  ASSERT (stat (BASE "link1", &st) == 0);
-  ASSERT (st.st_size == 2);
-  errno = 0;
-  ASSERT (lstat (BASE "link2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  ASSERT (symlink (BASE "link2", BASE "link2") == 0); /* Symlink loop.  */
-  ASSERT (func (BASE "link2", BASE "link2") == 0);
-  errno = 0;
-  ASSERT (func (BASE "link2/", BASE "link2") == -1);
-  ASSERT (errno == ELOOP || errno == ENOTDIR);
-  ASSERT (func (BASE "link2", BASE "link3") == 0);
-  ASSERT (unlink (BASE "link3") == 0);
-  ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Dangling link.  */
-  ASSERT (func (BASE "link2", BASE "link3") == 0);
-  errno = 0;
-  ASSERT (lstat (BASE "link2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link3", &st) == 0);
-  errno = 0; /* Trailing slash on dangling.  */
-  ASSERT (func (BASE "link3/", BASE "link2") == -1);
-  ASSERT (errno == ENOENT || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "link3", BASE "link2/") == -1);
-  ASSERT (errno == ENOENT || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (lstat (BASE "link2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link3", &st) == 0);
-  errno = 0; /* Trailing slash on link to file.  */
-  ASSERT (func (BASE "link1/", BASE "link2") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "link1", BASE "link3/") == -1);
-  ASSERT (errno == ENOENT || errno == ENOTDIR);
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Simple rename.  */
+    ASSERT (func (BASE "link1", BASE "link2") == 0);
+    ASSERT (stat (BASE "file", &st) == 0);
+    errno = 0;
+    ASSERT (lstat (BASE "link1", &st) == -1);
+    ASSERT (errno == ENOENT);
+    memset (&st, 0, sizeof st);
+    ASSERT (lstat (BASE "link2", &st) == 0);
+    ASSERT (S_ISLNK (st.st_mode));
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link2 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Overwrite.  */
+    ASSERT (symlink (BASE "nowhere", BASE "link1") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}nowhere
+         {BASE}link2 -> {BASE}file
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "link2", BASE "link1") == 0);
+      memset (&st, 0, sizeof st);
+      ASSERT (stat (BASE "link1", &st) == 0);
+      ASSERT (st.st_size == 2);
+      errno = 0;
+      ASSERT (lstat (BASE "link2", &st) == -1);
+      ASSERT (errno == ENOENT);
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Symlink loop.  */
+    ASSERT (symlink (BASE "link2", BASE "link2") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link2 -> {BASE}link2
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "link2", BASE "link2") == 0);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link2/", BASE "link2") == -1);
+      ASSERT (errno == ELOOP || errno == ENOTDIR);
+    }
+    ASSERT (func (BASE "link2", BASE "link3") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link3 -> {BASE}link2
+         {BASE}dir/
+     */
+    ASSERT (unlink (BASE "link3") == 0);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Dangling link.  */
+    ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link2 -> {BASE}nowhere
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "link2", BASE "link3") == 0);
+      errno = 0;
+      ASSERT (lstat (BASE "link2", &st) == -1);
+      ASSERT (errno == ENOENT);
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "link3", &st) == 0);
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}link3 -> {BASE}nowhere
+       {BASE}dir/
+   */
+  { /* Trailing slash on dangling.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "link3/", BASE "link2") == -1);
+      ASSERT (errno == ENOENT || errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link3", BASE "link2/") == -1);
+      ASSERT (errno == ENOENT || errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (lstat (BASE "link2", &st) == -1);
+      ASSERT (errno == ENOENT);
+    }
+    memset (&st, 0, sizeof st);
+    ASSERT (lstat (BASE "link3", &st) == 0);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}link3 -> {BASE}nowhere
+       {BASE}dir/
+   */
+  { /* Trailing slash on link to file.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1/", BASE "link2") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1", BASE "link3/") == -1);
+      ASSERT (errno == ENOENT || errno == ENOTDIR);
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}link3 -> {BASE}nowhere
+       {BASE}dir/
+   */
 
   /* Mixing symlink and file.  */
-  ASSERT (close (creat (BASE "file2", 0600)) == 0); /* File onto link.  */
-  ASSERT (func (BASE "file2", BASE "link3") == 0);
-  errno = 0;
-  ASSERT (stat (BASE "file2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link3", &st) == 0);
-  ASSERT (S_ISREG (st.st_mode));
-  ASSERT (unlink (BASE "link3") == 0);
-  ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Link onto file.  */
-  ASSERT (close (creat (BASE "file2", 0600)) == 0);
-  ASSERT (func (BASE "link2", BASE "file2") == 0);
-  errno = 0;
-  ASSERT (lstat (BASE "link2", &st) == -1);
-  ASSERT (errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "file2", &st) == 0);
-  ASSERT (S_ISLNK (st.st_mode));
-  ASSERT (unlink (BASE "file2") == 0);
-  errno = 0; /* Trailing slash.  */
-  ASSERT (func (BASE "file/", BASE "link1") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "file", BASE "link1/") == -1);
-  ASSERT (errno == ENOTDIR || errno == ENOENT);
-  errno = 0;
-  ASSERT (func (BASE "link1/", BASE "file") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "link1", BASE "file/") == -1);
-  ASSERT (errno == ENOTDIR || errno == ENOENT);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "file", &st) == 0);
-  ASSERT (S_ISREG (st.st_mode));
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link1", &st) == 0);
-  ASSERT (S_ISLNK (st.st_mode));
+
+  { /* File onto link.  */
+    ASSERT (close (creat (BASE "file2", 0600)) == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}file2
+         {BASE}link1 -> {BASE}file
+         {BASE}link3 -> {BASE}nowhere
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "file2", BASE "link3") == 0);
+      errno = 0;
+      ASSERT (stat (BASE "file2", &st) == -1);
+      ASSERT (errno == ENOENT);
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "link3", &st) == 0);
+      ASSERT (S_ISREG (st.st_mode));
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link3
+         {BASE}dir/
+     */
+    ASSERT (unlink (BASE "link3") == 0);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Link onto file.  */
+    ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link2 -> {BASE}nowhere
+         {BASE}dir/
+     */
+    ASSERT (close (creat (BASE "file2", 0600)) == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}file2
+         {BASE}link1 -> {BASE}file
+         {BASE}link2 -> {BASE}nowhere
+         {BASE}dir/
+     */
+    {
+      ASSERT (func (BASE "link2", BASE "file2") == 0);
+      errno = 0;
+      ASSERT (lstat (BASE "link2", &st) == -1);
+      ASSERT (errno == ENOENT);
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "file2", &st) == 0);
+      ASSERT (S_ISLNK (st.st_mode));
+    }
+    /* Files present here:
+         {BASE}file
+         {BASE}file2 -> {BASE}nowhere
+         {BASE}link1 -> {BASE}file
+         {BASE}dir/
+     */
+    ASSERT (unlink (BASE "file2") == 0);
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
+  { /* Trailing slash.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "file/", BASE "link1") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "file", BASE "link1/") == -1);
+      ASSERT (errno == ENOTDIR || errno == ENOENT);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1/", BASE "file") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1", BASE "file/") == -1);
+      ASSERT (errno == ENOTDIR || errno == ENOENT);
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "file", &st) == 0);
+      ASSERT (S_ISREG (st.st_mode));
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "link1", &st) == 0);
+      ASSERT (S_ISLNK (st.st_mode));
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
 
   /* Mixing symlink and directory.  */
-  errno = 0; /* Directory onto link.  */
-  ASSERT (func (BASE "dir", BASE "link1") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "dir/", BASE "link1") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "dir", BASE "link1/") == -1);
-  ASSERT (errno == ENOTDIR);
-  errno = 0; /* Link onto directory.  */
-  ASSERT (func (BASE "link1", BASE "dir") == -1);
-  ASSERT (errno == EISDIR || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "link1", BASE "dir/") == -1);
-  ASSERT (errno == EISDIR || errno == ENOTDIR);
-  errno = 0;
-  ASSERT (func (BASE "link1/", BASE "dir") == -1);
-  ASSERT (errno == ENOTDIR);
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "link1", &st) == 0);
-  ASSERT (S_ISLNK (st.st_mode));
-  memset (&st, 0, sizeof st);
-  ASSERT (lstat (BASE "dir", &st) == 0);
-  ASSERT (S_ISDIR (st.st_mode));
+
+  { /* Directory onto link.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "dir", BASE "link1") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "dir/", BASE "link1") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "dir", BASE "link1/") == -1);
+      ASSERT (errno == ENOTDIR);
+    }
+  }
+  { /* Link onto directory.  */
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1", BASE "dir") == -1);
+      ASSERT (errno == EISDIR || errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1", BASE "dir/") == -1);
+      ASSERT (errno == EISDIR || errno == ENOTDIR);
+    }
+    {
+      errno = 0;
+      ASSERT (func (BASE "link1/", BASE "dir") == -1);
+      ASSERT (errno == ENOTDIR);
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "link1", &st) == 0);
+      ASSERT (S_ISLNK (st.st_mode));
+      memset (&st, 0, sizeof st);
+      ASSERT (lstat (BASE "dir", &st) == 0);
+      ASSERT (S_ISDIR (st.st_mode));
+    }
+  }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}dir/
+   */
 
   /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
      leave "link-to-dir" dangling, but GNU rejects this.  POSIX
@@ -376,6 +853,12 @@ test_rename (int (*func) (char const *, char const *), bool print)
   {
     int result;
     ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
+    /* Files present here:
+         {BASE}file
+         {BASE}link1 -> {BASE}file
+         {BASE}link2 -> {BASE}dir2
+         {BASE}dir/
+     */
     errno = 0;
     result = func (BASE "dir", BASE "link2/");
     if (result == 0)
@@ -390,16 +873,24 @@ test_rename (int (*func) (char const *, char const *), bool print)
         memset (&st, 0, sizeof st);
         ASSERT (lstat (BASE "link2", &st) == 0);
         ASSERT (S_ISLNK (st.st_mode));
-        ASSERT (func (BASE "link2/", BASE "dir") == 0);
-        memset (&st, 0, sizeof st);
-        ASSERT (lstat (BASE "dir", &st) == 0);
-        ASSERT (S_ISDIR (st.st_mode));
-        errno = 0;
-        ASSERT (lstat (BASE "dir2", &st) == -1);
-        ASSERT (errno == ENOENT);
-        memset (&st, 0, sizeof st);
-        ASSERT (lstat (BASE "link2", &st) == 0);
-        ASSERT (S_ISLNK (st.st_mode));
+        /* Files present here:
+             {BASE}file
+             {BASE}link1 -> {BASE}file
+             {BASE}link2 -> {BASE}dir2
+             {BASE}dir2/
+         */
+        {
+          ASSERT (func (BASE "link2/", BASE "dir") == 0);
+          memset (&st, 0, sizeof st);
+          ASSERT (lstat (BASE "dir", &st) == 0);
+          ASSERT (S_ISDIR (st.st_mode));
+          errno = 0;
+          ASSERT (lstat (BASE "dir2", &st) == -1);
+          ASSERT (errno == ENOENT);
+          memset (&st, 0, sizeof st);
+          ASSERT (lstat (BASE "link2", &st) == 0);
+          ASSERT (S_ISLNK (st.st_mode));
+        }
       }
     else
       {
@@ -417,12 +908,18 @@ test_rename (int (*func) (char const *, char const *), bool print)
         ASSERT (S_ISLNK (st.st_mode));
         ASSERT (unlink (BASE "link2") == 0);
         ASSERT (symlink (BASE "dir", BASE "link2") == 0);
+        /* Files present here:
+             {BASE}file
+             {BASE}link1 -> {BASE}file
+             {BASE}link2 -> {BASE}dir
+             {BASE}dir/
+         */
         errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
         result = func (BASE "link2/", BASE "dir");
         if (result) /* GNU/Linux rejects attempts to use link2/.  */
           {
             ASSERT (result == -1);
-            ASSERT (errno == ENOTDIR);
+            ASSERT (errno == ENOTDIR || errno == EISDIR);
           }
         memset (&st, 0, sizeof st);
         ASSERT (lstat (BASE "dir", &st) == 0);
@@ -435,6 +932,12 @@ test_rename (int (*func) (char const *, char const *), bool print)
         ASSERT (S_ISLNK (st.st_mode));
       }
   }
+  /* Files present here:
+       {BASE}file
+       {BASE}link1 -> {BASE}file
+       {BASE}link2 -> {BASE}dir or {BASE}dir2
+       {BASE}dir/
+   */
 
   /* Clean up.  */
   ASSERT (unlink (BASE "file") == 0);