(root)/
m4-1.4.19/
tests/
test-rename.h
       1  /* Test of rename() function.
       2     Copyright (C) 2009-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3 of the License, or
       7     (at your option) any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  /* This file is designed to test both rename(a,b) and
      18     renameat(AT_FDCWD,a,AT_FDCWD,b).  FUNC is the function to test.
      19     Assumes that BASE and ASSERT are already defined, and that
      20     appropriate headers are already included.  If PRINT, warn before
      21     skipping symlink tests with status 77.  */
      22  
      23  /* Tests whether a file, given by a file name without slashes, exists in
      24     the current directory, by scanning the directory entries.  */
      25  static bool
      26  dentry_exists (const char *filename)
      27  {
      28    bool exists = false;
      29    DIR *dir = opendir (".");
      30  
      31    ASSERT (dir != NULL);
      32    for (;;)
      33      {
      34        struct dirent *d = readdir (dir);
      35        if (d == NULL)
      36          break;
      37        if (strcmp (d->d_name, filename) == 0)
      38          {
      39            exists = true;
      40            break;
      41          }
      42      }
      43    ASSERT (closedir (dir) == 0);
      44    return exists;
      45  }
      46  
      47  /* Asserts that a specific file, given by a file name without slashes, does
      48     not exist in the current directory.  */
      49  static void
      50  assert_nonexistent (const char *filename)
      51  {
      52    struct stat st;
      53  
      54    /* The usual way to test the presence of a file is via stat() or lstat().  */
      55    errno = 0;
      56    if (stat (filename, &st) == -1)
      57      ASSERT (errno == ENOENT);
      58    else
      59      {
      60        /* But after renaming a directory over an empty directory on an NFS-
      61           mounted file system, on Linux 2.6.18, for a period of 30 seconds the
      62           old directory name is "present" according to stat() but "nonexistent"
      63           according to dentry_exists().  */
      64        ASSERT (!dentry_exists (filename));
      65        /* Remove the old directory name, so that subsequent mkdir calls
      66           succeed.  */
      67        (void) rmdir (filename);
      68      }
      69  }
      70  
      71  static int
      72  test_rename (int (*func) (char const *, char const *), bool print)
      73  {
      74    /* Setup.  */
      75    struct stat st;
      76    int fd = creat (BASE "file", 0600);
      77    ASSERT (0 <= fd);
      78    ASSERT (write (fd, "hi", 2) == 2);
      79    ASSERT (close (fd) == 0);
      80    ASSERT (mkdir (BASE "dir", 0700) == 0);
      81  
      82    /* Files present here:
      83         {BASE}file
      84         {BASE}dir/
      85     */
      86  
      87    /* Obvious errors.  */
      88  
      89    { /* Missing source.  */
      90      {
      91        errno = 0;
      92        ASSERT (func (BASE "missing", BASE "missing") == -1);
      93        ASSERT (errno == ENOENT);
      94      }
      95      {
      96        errno = 0;
      97        ASSERT (func (BASE "missing/", BASE "missing") == -1);
      98        ASSERT (errno == ENOENT);
      99      }
     100      {
     101        errno = 0;
     102        ASSERT (func (BASE "missing", BASE "missing/") == -1);
     103        ASSERT (errno == ENOENT);
     104      }
     105    }
     106    { /* Empty operand.  */
     107      {
     108        errno = 0;
     109        ASSERT (func ("", BASE "missing") == -1);
     110        ASSERT (errno == ENOENT);
     111      }
     112      {
     113        errno = 0;
     114        ASSERT (func (BASE "file", "") == -1);
     115        ASSERT (errno == ENOENT);
     116      }
     117      {
     118        errno = 0;
     119        ASSERT (func (BASE "", "") == -1);
     120        ASSERT (errno == ENOENT);
     121      }
     122    }
     123  
     124    /* Files.  */
     125  
     126    { /* Trailing slash.  */
     127      {
     128        errno = 0;
     129        ASSERT (func (BASE "file", BASE "file2/") == -1);
     130        ASSERT (errno == ENOENT || errno == ENOTDIR);
     131      }
     132      {
     133        errno = 0;
     134        ASSERT (func (BASE "file/", BASE "file2") == -1);
     135        ASSERT (errno == ENOTDIR);
     136      }
     137      {
     138        errno = 0;
     139        ASSERT (stat (BASE "file2", &st) == -1);
     140        ASSERT (errno == ENOENT);
     141      }
     142    }
     143    { /* Simple rename.  */
     144      ASSERT (func (BASE "file", BASE "file2") == 0);
     145      errno = 0;
     146      ASSERT (stat (BASE "file", &st) == -1);
     147      ASSERT (errno == ENOENT);
     148      memset (&st, 0, sizeof st);
     149      ASSERT (stat (BASE "file2", &st) == 0);
     150      ASSERT (st.st_size == 2);
     151    }
     152    /* Files present here:
     153         {BASE}file2
     154         {BASE}dir/
     155     */
     156    { /* Overwrite.  */
     157      ASSERT (close (creat (BASE "file", 0600)) == 0);
     158      errno = 0;
     159      ASSERT (func (BASE "file2", BASE "file/") == -1);
     160      ASSERT (errno == ENOTDIR);
     161      ASSERT (func (BASE "file2", BASE "file") == 0);
     162      memset (&st, 0, sizeof st);
     163      ASSERT (stat (BASE "file", &st) == 0);
     164      ASSERT (st.st_size == 2);
     165      errno = 0;
     166      ASSERT (stat (BASE "file2", &st) == -1);
     167      ASSERT (errno == ENOENT);
     168    }
     169    /* Files present here:
     170         {BASE}file
     171         {BASE}dir/
     172     */
     173  
     174    /* Directories.  */
     175  
     176    { /* Simple rename.  */
     177      {
     178        ASSERT (func (BASE "dir", BASE "dir2/") == 0);
     179        errno = 0;
     180        ASSERT (stat (BASE "dir", &st) == -1);
     181        ASSERT (errno == ENOENT);
     182        ASSERT (stat (BASE "dir2", &st) == 0);
     183      }
     184      /* Files present here:
     185           {BASE}file
     186           {BASE}dir2/
     187       */
     188      {
     189        ASSERT (func (BASE "dir2/", BASE "dir") == 0);
     190        ASSERT (stat (BASE "dir", &st) == 0);
     191        errno = 0;
     192        ASSERT (stat (BASE "dir2", &st) == -1);
     193        ASSERT (errno == ENOENT);
     194      }
     195      /* Files present here:
     196           {BASE}file
     197           {BASE}dir/
     198       */
     199      {
     200        ASSERT (func (BASE "dir", BASE "dir2") == 0);
     201        errno = 0;
     202        ASSERT (stat (BASE "dir", &st) == -1);
     203        ASSERT (errno == ENOENT);
     204        ASSERT (stat (BASE "dir2", &st) == 0);
     205      }
     206      /* Files present here:
     207           {BASE}file
     208           {BASE}dir2/
     209       */
     210      { /* Empty onto empty.  */
     211        ASSERT (mkdir (BASE "dir", 0700) == 0);
     212        /* Files present here:
     213             {BASE}file
     214             {BASE}dir/
     215             {BASE}dir2/
     216         */
     217        ASSERT (func (BASE "dir2", BASE "dir") == 0);
     218        /* Files present here:
     219             {BASE}file
     220             {BASE}dir/
     221         */
     222        ASSERT (mkdir (BASE "dir2", 0700) == 0);
     223        /* Files present here:
     224             {BASE}file
     225             {BASE}dir/
     226             {BASE}dir2/
     227         */
     228        ASSERT (func (BASE "dir2", BASE "dir/") == 0);
     229        /* Files present here:
     230             {BASE}file
     231             {BASE}dir/
     232         */
     233        ASSERT (mkdir (BASE "dir2", 0700) == 0);
     234        /* Files present here:
     235             {BASE}file
     236             {BASE}dir/
     237             {BASE}dir2/
     238         */
     239        ASSERT (func (BASE "dir2/", BASE "dir") == 0);
     240        /* Files present here:
     241             {BASE}file
     242             {BASE}dir/
     243         */
     244        ASSERT (mkdir (BASE "dir2", 0700) == 0);
     245      }
     246      /* Files present here:
     247           {BASE}file
     248           {BASE}dir/
     249           {BASE}dir2/
     250       */
     251      { /* Empty onto full.  */
     252        ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
     253        /* Files present here:
     254             {BASE}file
     255             {BASE}dir/
     256             {BASE}dir/file
     257             {BASE}dir2/
     258         */
     259        {
     260          errno = 0;
     261          ASSERT (func (BASE "dir2", BASE "dir") == -1);
     262          ASSERT (errno == EEXIST || errno == ENOTEMPTY);
     263        }
     264        {
     265          errno = 0;
     266          ASSERT (func (BASE "dir2/", BASE "dir") == -1);
     267          ASSERT (errno == EEXIST || errno == ENOTEMPTY);
     268        }
     269        {
     270          errno = 0;
     271          ASSERT (func (BASE "dir2", BASE "dir/") == -1);
     272          ASSERT (errno == EEXIST || errno == ENOTEMPTY);
     273        }
     274      }
     275      { /* Full onto empty.  */
     276        ASSERT (func (BASE "dir", BASE "dir2") == 0);
     277        assert_nonexistent (BASE "dir");
     278        ASSERT (stat (BASE "dir2/file", &st) == 0);
     279        /* Files present here:
     280             {BASE}file
     281             {BASE}dir2/
     282             {BASE}dir2/file
     283         */
     284        ASSERT (mkdir (BASE "dir", 0700) == 0);
     285        /* Files present here:
     286             {BASE}file
     287             {BASE}dir/
     288             {BASE}dir2/
     289             {BASE}dir2/file
     290         */
     291        {
     292          ASSERT (func (BASE "dir2/", BASE "dir") == 0);
     293          ASSERT (stat (BASE "dir/file", &st) == 0);
     294          errno = 0;
     295          ASSERT (stat (BASE "dir2", &st) == -1);
     296          ASSERT (errno == ENOENT);
     297        }
     298        /* Files present here:
     299             {BASE}file
     300             {BASE}dir/
     301             {BASE}dir/file
     302         */
     303        ASSERT (mkdir (BASE "dir2", 0700) == 0);
     304        /* Files present here:
     305             {BASE}file
     306             {BASE}dir/
     307             {BASE}dir/file
     308             {BASE}dir2/
     309         */
     310        {
     311          ASSERT (func (BASE "dir", BASE "dir2/") == 0);
     312          assert_nonexistent (BASE "dir");
     313          ASSERT (stat (BASE "dir2/file", &st) == 0);
     314        }
     315        /* Files present here:
     316             {BASE}file
     317             {BASE}dir2/
     318             {BASE}dir2/file
     319         */
     320        ASSERT (unlink (BASE "dir2/file") == 0);
     321      }
     322      /* Files present here:
     323           {BASE}file
     324           {BASE}dir2/
     325       */
     326      { /* Reject trailing dot.  */
     327        {
     328          errno = 0;
     329          ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
     330          ASSERT (errno == EINVAL || errno == ENOENT);
     331        }
     332        ASSERT (mkdir (BASE "dir", 0700) == 0);
     333        /* Files present here:
     334             {BASE}file
     335             {BASE}dir/
     336             {BASE}dir2/
     337         */
     338        {
     339          errno = 0;
     340          ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
     341          ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
     342                  || errno == ENOTEMPTY || errno == EEXIST
     343                  || errno == ENOENT /* WSL */);
     344        }
     345        {
     346          errno = 0;
     347          ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
     348          ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
     349                  || errno == ENOENT /* WSL */);
     350        }
     351        ASSERT (rmdir (BASE "dir") == 0);
     352        /* Files present here:
     353             {BASE}file
     354             {BASE}dir2/
     355         */
     356        {
     357          errno = 0;
     358          ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
     359          ASSERT (errno == EINVAL || errno == ENOENT);
     360        }
     361        ASSERT (mkdir (BASE "dir", 0700) == 0);
     362        /* Files present here:
     363             {BASE}file
     364             {BASE}dir/
     365             {BASE}dir2/
     366         */
     367        {
     368          errno = 0;
     369          ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
     370          ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR
     371                  || errno == ENOTEMPTY || errno == EEXIST
     372                  || errno == ENOENT /* WSL */);
     373        }
     374        {
     375          errno = 0;
     376          ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
     377          ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST
     378                  || errno == ENOENT /* WSL */);
     379        }
     380        ASSERT (rmdir (BASE "dir2") == 0);
     381        /* Files present here:
     382             {BASE}file
     383             {BASE}dir/
     384         */
     385      }
     386      { /* Move into subdir.  */
     387        {
     388          errno = 0;
     389          ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
     390          ASSERT (errno == EINVAL || errno == EACCES);
     391        }
     392        {
     393          errno = 0;
     394          ASSERT (stat (BASE "dir/sub", &st) == -1);
     395          ASSERT (errno == ENOENT);
     396        }
     397        ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
     398        /* Files present here:
     399             {BASE}file
     400             {BASE}dir/
     401             {BASE}dir/sub/
     402         */
     403        {
     404          errno = 0;
     405          ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
     406          ASSERT (errno == EINVAL);
     407          ASSERT (stat (BASE "dir/sub", &st) == 0);
     408        }
     409        ASSERT (rmdir (BASE "dir/sub") == 0);
     410      }
     411    }
     412    /* Files present here:
     413         {BASE}file
     414         {BASE}dir/
     415     */
     416  
     417    /* Mixing file and directory.  */
     418  
     419    {
     420      { /* File onto dir.  */
     421        {
     422          errno = 0;
     423          ASSERT (func (BASE "file", BASE "dir") == -1);
     424          ASSERT (errno == EISDIR || errno == ENOTDIR);
     425        }
     426        {
     427          errno = 0;
     428          ASSERT (func (BASE "file", BASE "dir/") == -1);
     429          ASSERT (errno == EISDIR || errno == ENOTDIR);
     430        }
     431      }
     432      { /* Dir onto file.  */
     433        {
     434          errno = 0;
     435          ASSERT (func (BASE "dir", BASE "file") == -1);
     436          ASSERT (errno == ENOTDIR);
     437        }
     438        {
     439          errno = 0;
     440          ASSERT (func (BASE "dir/", BASE "file") == -1);
     441          ASSERT (errno == ENOTDIR);
     442        }
     443      }
     444    }
     445  
     446    /* Hard links.  */
     447  
     448    { /* File onto self.  */
     449      ASSERT (func (BASE "file", BASE "file") == 0);
     450      memset (&st, 0, sizeof st);
     451      ASSERT (stat (BASE "file", &st) == 0);
     452      ASSERT (st.st_size == 2);
     453    }
     454    /* Files present here:
     455         {BASE}file
     456         {BASE}dir/
     457     */
     458    { /* Empty dir onto self.  */
     459      ASSERT (func (BASE "dir", BASE "dir") == 0);
     460      ASSERT (stat (BASE "dir", &st) == 0);
     461    }
     462    /* Files present here:
     463         {BASE}file
     464         {BASE}dir/
     465     */
     466    ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
     467    /* Files present here:
     468         {BASE}file
     469         {BASE}dir/
     470         {BASE}dir/file
     471     */
     472    { /* Full dir onto self.  */
     473      ASSERT (func (BASE "dir", BASE "dir") == 0);
     474    }
     475    ASSERT (unlink (BASE "dir/file") == 0);
     476    /* Files present here:
     477         {BASE}file
     478         {BASE}dir/
     479     */
     480    {
     481      /*  Not all file systems support link.  Mingw doesn't have
     482          reliable st_nlink on hard links, but our implementation does
     483          fail with EPERM on poor file systems, and we can detect the
     484          inferior stat() via st_ino.  Cygwin 1.5.x copies rather than
     485          links files on those file systems, but there, st_nlink and
     486          st_ino are reliable.  */
     487      int ret = link (BASE "file", BASE "file2");
     488      if (!ret)
     489        {
     490          memset (&st, 0, sizeof st);
     491          ASSERT (stat (BASE "file2", &st) == 0);
     492          if (st.st_ino && st.st_nlink != 2)
     493            {
     494              ASSERT (unlink (BASE "file2") == 0);
     495              errno = EPERM;
     496              ret = -1;
     497            }
     498        }
     499      if (ret == -1)
     500        {
     501          /* If the device does not support hard links, errno is
     502             EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
     503          switch (errno)
     504            {
     505            case EPERM:
     506            case EOPNOTSUPP:
     507              if (print)
     508                fputs ("skipping test: "
     509                       "hard links not supported on this file system\n",
     510                       stderr);
     511              ASSERT (unlink (BASE "file") == 0);
     512              ASSERT (rmdir (BASE "dir") == 0);
     513              return 77;
     514            default:
     515              perror ("link");
     516              return 1;
     517            }
     518        }
     519      ASSERT (ret == 0);
     520    }
     521    /* Files present here:
     522         {BASE}file
     523         {BASE}file2       (hard link to file)
     524         {BASE}dir/
     525     */
     526    { /* File onto hard link.  */
     527      ASSERT (func (BASE "file", BASE "file2") == 0);
     528      memset (&st, 0, sizeof st);
     529      if (stat (BASE "file", &st) != 0)
     530        {
     531          /* This can happen on NetBSD.  */
     532          ASSERT (errno == ENOENT);
     533          ASSERT (link (BASE "file2", BASE "file") == 0);
     534          ASSERT (stat (BASE "file", &st) == 0);
     535        }
     536      ASSERT (st.st_size == 2);
     537      memset (&st, 0, sizeof st);
     538      ASSERT (stat (BASE "file2", &st) == 0);
     539      ASSERT (st.st_size == 2);
     540    }
     541    /* Files present here:
     542         {BASE}file
     543         {BASE}file2
     544         {BASE}dir/
     545     */
     546    ASSERT (unlink (BASE "file2") == 0);
     547    /* Files present here:
     548         {BASE}file
     549         {BASE}dir/
     550     */
     551  
     552    /* Symlinks.  */
     553  
     554    if (symlink (BASE "file", BASE "link1"))
     555      {
     556        if (print)
     557          fputs ("skipping test: symlinks not supported on this file system\n",
     558                 stderr);
     559        ASSERT (unlink (BASE "file") == 0);
     560        ASSERT (rmdir (BASE "dir") == 0);
     561        return 77;
     562      }
     563    /* Files present here:
     564         {BASE}file
     565         {BASE}link1 -> {BASE}file
     566         {BASE}dir/
     567     */
     568    { /* Simple rename.  */
     569      ASSERT (func (BASE "link1", BASE "link2") == 0);
     570      ASSERT (stat (BASE "file", &st) == 0);
     571      errno = 0;
     572      ASSERT (lstat (BASE "link1", &st) == -1);
     573      ASSERT (errno == ENOENT);
     574      memset (&st, 0, sizeof st);
     575      ASSERT (lstat (BASE "link2", &st) == 0);
     576      ASSERT (S_ISLNK (st.st_mode));
     577    }
     578    /* Files present here:
     579         {BASE}file
     580         {BASE}link2 -> {BASE}file
     581         {BASE}dir/
     582     */
     583    { /* Overwrite.  */
     584      ASSERT (symlink (BASE "nowhere", BASE "link1") == 0);
     585      /* Files present here:
     586           {BASE}file
     587           {BASE}link1 -> {BASE}nowhere
     588           {BASE}link2 -> {BASE}file
     589           {BASE}dir/
     590       */
     591      {
     592        ASSERT (func (BASE "link2", BASE "link1") == 0);
     593        memset (&st, 0, sizeof st);
     594        ASSERT (stat (BASE "link1", &st) == 0);
     595        ASSERT (st.st_size == 2);
     596        errno = 0;
     597        ASSERT (lstat (BASE "link2", &st) == -1);
     598        ASSERT (errno == ENOENT);
     599      }
     600    }
     601    /* Files present here:
     602         {BASE}file
     603         {BASE}link1 -> {BASE}file
     604         {BASE}dir/
     605     */
     606    { /* Symlink loop.  */
     607      ASSERT (symlink (BASE "link2", BASE "link2") == 0);
     608      /* Files present here:
     609           {BASE}file
     610           {BASE}link1 -> {BASE}file
     611           {BASE}link2 -> {BASE}link2
     612           {BASE}dir/
     613       */
     614      {
     615        ASSERT (func (BASE "link2", BASE "link2") == 0);
     616      }
     617      {
     618        errno = 0;
     619        ASSERT (func (BASE "link2/", BASE "link2") == -1);
     620        ASSERT (errno == ELOOP || errno == ENOTDIR);
     621      }
     622      ASSERT (func (BASE "link2", BASE "link3") == 0);
     623      /* Files present here:
     624           {BASE}file
     625           {BASE}link1 -> {BASE}file
     626           {BASE}link3 -> {BASE}link2
     627           {BASE}dir/
     628       */
     629      ASSERT (unlink (BASE "link3") == 0);
     630    }
     631    /* Files present here:
     632         {BASE}file
     633         {BASE}link1 -> {BASE}file
     634         {BASE}dir/
     635     */
     636    { /* Dangling link.  */
     637      ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
     638      /* Files present here:
     639           {BASE}file
     640           {BASE}link1 -> {BASE}file
     641           {BASE}link2 -> {BASE}nowhere
     642           {BASE}dir/
     643       */
     644      {
     645        ASSERT (func (BASE "link2", BASE "link3") == 0);
     646        errno = 0;
     647        ASSERT (lstat (BASE "link2", &st) == -1);
     648        ASSERT (errno == ENOENT);
     649        memset (&st, 0, sizeof st);
     650        ASSERT (lstat (BASE "link3", &st) == 0);
     651      }
     652    }
     653    /* Files present here:
     654         {BASE}file
     655         {BASE}link1 -> {BASE}file
     656         {BASE}link3 -> {BASE}nowhere
     657         {BASE}dir/
     658     */
     659    { /* Trailing slash on dangling.  */
     660      {
     661        errno = 0;
     662        ASSERT (func (BASE "link3/", BASE "link2") == -1);
     663        ASSERT (errno == ENOENT || errno == ENOTDIR);
     664      }
     665      {
     666        errno = 0;
     667        ASSERT (func (BASE "link3", BASE "link2/") == -1);
     668        ASSERT (errno == ENOENT || errno == ENOTDIR);
     669      }
     670      {
     671        errno = 0;
     672        ASSERT (lstat (BASE "link2", &st) == -1);
     673        ASSERT (errno == ENOENT);
     674      }
     675      memset (&st, 0, sizeof st);
     676      ASSERT (lstat (BASE "link3", &st) == 0);
     677    }
     678    /* Files present here:
     679         {BASE}file
     680         {BASE}link1 -> {BASE}file
     681         {BASE}link3 -> {BASE}nowhere
     682         {BASE}dir/
     683     */
     684    { /* Trailing slash on link to file.  */
     685      {
     686        errno = 0;
     687        ASSERT (func (BASE "link1/", BASE "link2") == -1);
     688        ASSERT (errno == ENOTDIR);
     689      }
     690      {
     691        errno = 0;
     692        ASSERT (func (BASE "link1", BASE "link3/") == -1);
     693        ASSERT (errno == ENOENT || errno == ENOTDIR);
     694      }
     695    }
     696    /* Files present here:
     697         {BASE}file
     698         {BASE}link1 -> {BASE}file
     699         {BASE}link3 -> {BASE}nowhere
     700         {BASE}dir/
     701     */
     702  
     703    /* Mixing symlink and file.  */
     704  
     705    { /* File onto link.  */
     706      ASSERT (close (creat (BASE "file2", 0600)) == 0);
     707      /* Files present here:
     708           {BASE}file
     709           {BASE}file2
     710           {BASE}link1 -> {BASE}file
     711           {BASE}link3 -> {BASE}nowhere
     712           {BASE}dir/
     713       */
     714      {
     715        ASSERT (func (BASE "file2", BASE "link3") == 0);
     716        errno = 0;
     717        ASSERT (stat (BASE "file2", &st) == -1);
     718        ASSERT (errno == ENOENT);
     719        memset (&st, 0, sizeof st);
     720        ASSERT (lstat (BASE "link3", &st) == 0);
     721        ASSERT (S_ISREG (st.st_mode));
     722      }
     723      /* Files present here:
     724           {BASE}file
     725           {BASE}link1 -> {BASE}file
     726           {BASE}link3
     727           {BASE}dir/
     728       */
     729      ASSERT (unlink (BASE "link3") == 0);
     730    }
     731    /* Files present here:
     732         {BASE}file
     733         {BASE}link1 -> {BASE}file
     734         {BASE}dir/
     735     */
     736    { /* Link onto file.  */
     737      ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
     738      /* Files present here:
     739           {BASE}file
     740           {BASE}link1 -> {BASE}file
     741           {BASE}link2 -> {BASE}nowhere
     742           {BASE}dir/
     743       */
     744      ASSERT (close (creat (BASE "file2", 0600)) == 0);
     745      /* Files present here:
     746           {BASE}file
     747           {BASE}file2
     748           {BASE}link1 -> {BASE}file
     749           {BASE}link2 -> {BASE}nowhere
     750           {BASE}dir/
     751       */
     752      {
     753        ASSERT (func (BASE "link2", BASE "file2") == 0);
     754        errno = 0;
     755        ASSERT (lstat (BASE "link2", &st) == -1);
     756        ASSERT (errno == ENOENT);
     757        memset (&st, 0, sizeof st);
     758        ASSERT (lstat (BASE "file2", &st) == 0);
     759        ASSERT (S_ISLNK (st.st_mode));
     760      }
     761      /* Files present here:
     762           {BASE}file
     763           {BASE}file2 -> {BASE}nowhere
     764           {BASE}link1 -> {BASE}file
     765           {BASE}dir/
     766       */
     767      ASSERT (unlink (BASE "file2") == 0);
     768    }
     769    /* Files present here:
     770         {BASE}file
     771         {BASE}link1 -> {BASE}file
     772         {BASE}dir/
     773     */
     774    { /* Trailing slash.  */
     775      {
     776        errno = 0;
     777        ASSERT (func (BASE "file/", BASE "link1") == -1);
     778        ASSERT (errno == ENOTDIR);
     779      }
     780      {
     781        errno = 0;
     782        ASSERT (func (BASE "file", BASE "link1/") == -1);
     783        ASSERT (errno == ENOTDIR || errno == ENOENT);
     784      }
     785      {
     786        errno = 0;
     787        ASSERT (func (BASE "link1/", BASE "file") == -1);
     788        ASSERT (errno == ENOTDIR);
     789      }
     790      {
     791        errno = 0;
     792        ASSERT (func (BASE "link1", BASE "file/") == -1);
     793        ASSERT (errno == ENOTDIR || errno == ENOENT);
     794        memset (&st, 0, sizeof st);
     795        ASSERT (lstat (BASE "file", &st) == 0);
     796        ASSERT (S_ISREG (st.st_mode));
     797        memset (&st, 0, sizeof st);
     798        ASSERT (lstat (BASE "link1", &st) == 0);
     799        ASSERT (S_ISLNK (st.st_mode));
     800      }
     801    }
     802    /* Files present here:
     803         {BASE}file
     804         {BASE}link1 -> {BASE}file
     805         {BASE}dir/
     806     */
     807  
     808    /* Mixing symlink and directory.  */
     809  
     810    { /* Directory onto link.  */
     811      {
     812        errno = 0;
     813        ASSERT (func (BASE "dir", BASE "link1") == -1);
     814        ASSERT (errno == ENOTDIR);
     815      }
     816      {
     817        errno = 0;
     818        ASSERT (func (BASE "dir/", BASE "link1") == -1);
     819        ASSERT (errno == ENOTDIR);
     820      }
     821      {
     822        errno = 0;
     823        ASSERT (func (BASE "dir", BASE "link1/") == -1);
     824        ASSERT (errno == ENOTDIR);
     825      }
     826    }
     827    { /* Link onto directory.  */
     828      {
     829        errno = 0;
     830        ASSERT (func (BASE "link1", BASE "dir") == -1);
     831        ASSERT (errno == EISDIR || errno == ENOTDIR);
     832      }
     833      {
     834        errno = 0;
     835        ASSERT (func (BASE "link1", BASE "dir/") == -1);
     836        ASSERT (errno == EISDIR || errno == ENOTDIR);
     837      }
     838      {
     839        errno = 0;
     840        ASSERT (func (BASE "link1/", BASE "dir") == -1);
     841        ASSERT (errno == ENOTDIR);
     842        memset (&st, 0, sizeof st);
     843        ASSERT (lstat (BASE "link1", &st) == 0);
     844        ASSERT (S_ISLNK (st.st_mode));
     845        memset (&st, 0, sizeof st);
     846        ASSERT (lstat (BASE "dir", &st) == 0);
     847        ASSERT (S_ISDIR (st.st_mode));
     848      }
     849    }
     850    /* Files present here:
     851         {BASE}file
     852         {BASE}link1 -> {BASE}file
     853         {BASE}dir/
     854     */
     855  
     856    /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
     857       leave "link-to-dir" dangling, but GNU rejects this.  POSIX
     858       requires rename("dir","dangling/") to create the directory so
     859       that "dangling/" now resolves, but GNU rejects this.  While we
     860       prefer GNU behavior, we don't enforce it.  However, we do test
     861       that the system either follows POSIX in both cases, or follows
     862       GNU.  */
     863    {
     864      int result;
     865      ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
     866      /* Files present here:
     867           {BASE}file
     868           {BASE}link1 -> {BASE}file
     869           {BASE}link2 -> {BASE}dir2
     870           {BASE}dir/
     871       */
     872      errno = 0;
     873      result = func (BASE "dir", BASE "link2/");
     874      if (result == 0)
     875        {
     876          /* POSIX.  */
     877          errno = 0;
     878          ASSERT (lstat (BASE "dir", &st) == -1);
     879          ASSERT (errno == ENOENT);
     880          memset (&st, 0, sizeof st);
     881          ASSERT (lstat (BASE "dir2", &st) == 0);
     882          ASSERT (S_ISDIR (st.st_mode));
     883          memset (&st, 0, sizeof st);
     884          ASSERT (lstat (BASE "link2", &st) == 0);
     885          ASSERT (S_ISLNK (st.st_mode));
     886          /* Files present here:
     887               {BASE}file
     888               {BASE}link1 -> {BASE}file
     889               {BASE}link2 -> {BASE}dir2
     890               {BASE}dir2/
     891           */
     892          {
     893            ASSERT (func (BASE "link2/", BASE "dir") == 0);
     894            memset (&st, 0, sizeof st);
     895            ASSERT (lstat (BASE "dir", &st) == 0);
     896            ASSERT (S_ISDIR (st.st_mode));
     897            errno = 0;
     898            ASSERT (lstat (BASE "dir2", &st) == -1);
     899            ASSERT (errno == ENOENT);
     900            memset (&st, 0, sizeof st);
     901            ASSERT (lstat (BASE "link2", &st) == 0);
     902            ASSERT (S_ISLNK (st.st_mode));
     903          }
     904        }
     905      else
     906        {
     907          /* GNU.  */
     908          ASSERT (result == -1);
     909          ASSERT (errno == ENOTDIR);
     910          memset (&st, 0, sizeof st);
     911          ASSERT (lstat (BASE "dir", &st) == 0);
     912          ASSERT (S_ISDIR (st.st_mode));
     913          errno = 0;
     914          ASSERT (lstat (BASE "dir2", &st) == -1);
     915          ASSERT (errno == ENOENT);
     916          memset (&st, 0, sizeof st);
     917          ASSERT (lstat (BASE "link2", &st) == 0);
     918          ASSERT (S_ISLNK (st.st_mode));
     919          ASSERT (unlink (BASE "link2") == 0);
     920          ASSERT (symlink (BASE "dir", BASE "link2") == 0);
     921          /* Files present here:
     922               {BASE}file
     923               {BASE}link1 -> {BASE}file
     924               {BASE}link2 -> {BASE}dir
     925               {BASE}dir/
     926           */
     927          errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
     928          result = func (BASE "link2/", BASE "dir");
     929          if (result) /* GNU/Linux rejects attempts to use link2/.  */
     930            {
     931              ASSERT (result == -1);
     932              ASSERT (errno == ENOTDIR || errno == EISDIR);
     933            }
     934          memset (&st, 0, sizeof st);
     935          ASSERT (lstat (BASE "dir", &st) == 0);
     936          ASSERT (S_ISDIR (st.st_mode));
     937          errno = 0;
     938          ASSERT (lstat (BASE "dir2", &st) == -1);
     939          ASSERT (errno == ENOENT);
     940          memset (&st, 0, sizeof st);
     941          ASSERT (lstat (BASE "link2", &st) == 0);
     942          ASSERT (S_ISLNK (st.st_mode));
     943        }
     944    }
     945    /* Files present here:
     946         {BASE}file
     947         {BASE}link1 -> {BASE}file
     948         {BASE}link2 -> {BASE}dir or {BASE}dir2
     949         {BASE}dir/
     950     */
     951  
     952    /* Clean up.  */
     953    ASSERT (unlink (BASE "file") == 0);
     954    ASSERT (rmdir (BASE "dir") == 0);
     955    ASSERT (unlink (BASE "link1") == 0);
     956    ASSERT (unlink (BASE "link2") == 0);
     957  
     958    return 0;
     959  }