(root)/
coreutils-9.4/
gnulib-tests/
test-rename.h
       1  /* Test of rename() function.
       2     Copyright (C) 2009-2023 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,
     503             EOPNOTSUPP on FreeBSD,
     504             EACCES on Android within Termux.  */
     505          switch (errno)
     506            {
     507            case EPERM:
     508            case EOPNOTSUPP:
     509            #if defined __ANDROID__
     510            case EACCES:
     511            #endif
     512              if (print)
     513                fputs ("skipping test: "
     514                       "hard links not supported on this file system\n",
     515                       stderr);
     516              ASSERT (unlink (BASE "file") == 0);
     517              ASSERT (rmdir (BASE "dir") == 0);
     518              return 77;
     519            default:
     520              perror ("link");
     521              return 1;
     522            }
     523        }
     524      ASSERT (ret == 0);
     525    }
     526    /* Files present here:
     527         {BASE}file
     528         {BASE}file2       (hard link to file)
     529         {BASE}dir/
     530     */
     531    { /* File onto hard link.  */
     532      ASSERT (func (BASE "file", BASE "file2") == 0);
     533      memset (&st, 0, sizeof st);
     534      if (stat (BASE "file", &st) != 0)
     535        {
     536          /* This can happen on NetBSD.  */
     537          ASSERT (errno == ENOENT);
     538          ASSERT (link (BASE "file2", BASE "file") == 0);
     539          ASSERT (stat (BASE "file", &st) == 0);
     540        }
     541      ASSERT (st.st_size == 2);
     542      memset (&st, 0, sizeof st);
     543      ASSERT (stat (BASE "file2", &st) == 0);
     544      ASSERT (st.st_size == 2);
     545    }
     546    /* Files present here:
     547         {BASE}file
     548         {BASE}file2
     549         {BASE}dir/
     550     */
     551    ASSERT (unlink (BASE "file2") == 0);
     552    /* Files present here:
     553         {BASE}file
     554         {BASE}dir/
     555     */
     556  
     557    /* Symlinks.  */
     558  
     559    if (symlink (BASE "file", BASE "link1"))
     560      {
     561        if (print)
     562          fputs ("skipping test: symlinks not supported on this file system\n",
     563                 stderr);
     564        ASSERT (unlink (BASE "file") == 0);
     565        ASSERT (rmdir (BASE "dir") == 0);
     566        return 77;
     567      }
     568    /* Files present here:
     569         {BASE}file
     570         {BASE}link1 -> {BASE}file
     571         {BASE}dir/
     572     */
     573    { /* Simple rename.  */
     574      ASSERT (func (BASE "link1", BASE "link2") == 0);
     575      ASSERT (stat (BASE "file", &st) == 0);
     576      errno = 0;
     577      ASSERT (lstat (BASE "link1", &st) == -1);
     578      ASSERT (errno == ENOENT);
     579      memset (&st, 0, sizeof st);
     580      ASSERT (lstat (BASE "link2", &st) == 0);
     581      ASSERT (S_ISLNK (st.st_mode));
     582    }
     583    /* Files present here:
     584         {BASE}file
     585         {BASE}link2 -> {BASE}file
     586         {BASE}dir/
     587     */
     588    { /* Overwrite.  */
     589      ASSERT (symlink (BASE "nowhere", BASE "link1") == 0);
     590      /* Files present here:
     591           {BASE}file
     592           {BASE}link1 -> {BASE}nowhere
     593           {BASE}link2 -> {BASE}file
     594           {BASE}dir/
     595       */
     596      {
     597        ASSERT (func (BASE "link2", BASE "link1") == 0);
     598        memset (&st, 0, sizeof st);
     599        ASSERT (stat (BASE "link1", &st) == 0);
     600        ASSERT (st.st_size == 2);
     601        errno = 0;
     602        ASSERT (lstat (BASE "link2", &st) == -1);
     603        ASSERT (errno == ENOENT);
     604      }
     605    }
     606    /* Files present here:
     607         {BASE}file
     608         {BASE}link1 -> {BASE}file
     609         {BASE}dir/
     610     */
     611    { /* Symlink loop.  */
     612      ASSERT (symlink (BASE "link2", BASE "link2") == 0);
     613      /* Files present here:
     614           {BASE}file
     615           {BASE}link1 -> {BASE}file
     616           {BASE}link2 -> {BASE}link2
     617           {BASE}dir/
     618       */
     619      {
     620        ASSERT (func (BASE "link2", BASE "link2") == 0);
     621      }
     622      {
     623        errno = 0;
     624        ASSERT (func (BASE "link2/", BASE "link2") == -1);
     625        ASSERT (errno == ELOOP || errno == ENOTDIR);
     626      }
     627      ASSERT (func (BASE "link2", BASE "link3") == 0);
     628      /* Files present here:
     629           {BASE}file
     630           {BASE}link1 -> {BASE}file
     631           {BASE}link3 -> {BASE}link2
     632           {BASE}dir/
     633       */
     634      ASSERT (unlink (BASE "link3") == 0);
     635    }
     636    /* Files present here:
     637         {BASE}file
     638         {BASE}link1 -> {BASE}file
     639         {BASE}dir/
     640     */
     641    { /* Dangling link.  */
     642      ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
     643      /* Files present here:
     644           {BASE}file
     645           {BASE}link1 -> {BASE}file
     646           {BASE}link2 -> {BASE}nowhere
     647           {BASE}dir/
     648       */
     649      {
     650        ASSERT (func (BASE "link2", BASE "link3") == 0);
     651        errno = 0;
     652        ASSERT (lstat (BASE "link2", &st) == -1);
     653        ASSERT (errno == ENOENT);
     654        memset (&st, 0, sizeof st);
     655        ASSERT (lstat (BASE "link3", &st) == 0);
     656      }
     657    }
     658    /* Files present here:
     659         {BASE}file
     660         {BASE}link1 -> {BASE}file
     661         {BASE}link3 -> {BASE}nowhere
     662         {BASE}dir/
     663     */
     664    { /* Trailing slash on dangling.  */
     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 (func (BASE "link3", BASE "link2/") == -1);
     673        ASSERT (errno == ENOENT || errno == ENOTDIR);
     674      }
     675      {
     676        errno = 0;
     677        ASSERT (lstat (BASE "link2", &st) == -1);
     678        ASSERT (errno == ENOENT);
     679      }
     680      memset (&st, 0, sizeof st);
     681      ASSERT (lstat (BASE "link3", &st) == 0);
     682    }
     683    /* Files present here:
     684         {BASE}file
     685         {BASE}link1 -> {BASE}file
     686         {BASE}link3 -> {BASE}nowhere
     687         {BASE}dir/
     688     */
     689    { /* Trailing slash on link to file.  */
     690      {
     691        errno = 0;
     692        ASSERT (func (BASE "link1/", BASE "link2") == -1);
     693        ASSERT (errno == ENOTDIR);
     694      }
     695      {
     696        errno = 0;
     697        ASSERT (func (BASE "link1", BASE "link3/") == -1);
     698        ASSERT (errno == ENOENT || errno == ENOTDIR);
     699      }
     700    }
     701    /* Files present here:
     702         {BASE}file
     703         {BASE}link1 -> {BASE}file
     704         {BASE}link3 -> {BASE}nowhere
     705         {BASE}dir/
     706     */
     707  
     708    /* Mixing symlink and file.  */
     709  
     710    { /* File onto link.  */
     711      ASSERT (close (creat (BASE "file2", 0600)) == 0);
     712      /* Files present here:
     713           {BASE}file
     714           {BASE}file2
     715           {BASE}link1 -> {BASE}file
     716           {BASE}link3 -> {BASE}nowhere
     717           {BASE}dir/
     718       */
     719      {
     720        ASSERT (func (BASE "file2", BASE "link3") == 0);
     721        errno = 0;
     722        ASSERT (stat (BASE "file2", &st) == -1);
     723        ASSERT (errno == ENOENT);
     724        memset (&st, 0, sizeof st);
     725        ASSERT (lstat (BASE "link3", &st) == 0);
     726        ASSERT (S_ISREG (st.st_mode));
     727      }
     728      /* Files present here:
     729           {BASE}file
     730           {BASE}link1 -> {BASE}file
     731           {BASE}link3
     732           {BASE}dir/
     733       */
     734      ASSERT (unlink (BASE "link3") == 0);
     735    }
     736    /* Files present here:
     737         {BASE}file
     738         {BASE}link1 -> {BASE}file
     739         {BASE}dir/
     740     */
     741    { /* Link onto file.  */
     742      ASSERT (symlink (BASE "nowhere", BASE "link2") == 0);
     743      /* Files present here:
     744           {BASE}file
     745           {BASE}link1 -> {BASE}file
     746           {BASE}link2 -> {BASE}nowhere
     747           {BASE}dir/
     748       */
     749      ASSERT (close (creat (BASE "file2", 0600)) == 0);
     750      /* Files present here:
     751           {BASE}file
     752           {BASE}file2
     753           {BASE}link1 -> {BASE}file
     754           {BASE}link2 -> {BASE}nowhere
     755           {BASE}dir/
     756       */
     757      {
     758        ASSERT (func (BASE "link2", BASE "file2") == 0);
     759        errno = 0;
     760        ASSERT (lstat (BASE "link2", &st) == -1);
     761        ASSERT (errno == ENOENT);
     762        memset (&st, 0, sizeof st);
     763        ASSERT (lstat (BASE "file2", &st) == 0);
     764        ASSERT (S_ISLNK (st.st_mode));
     765      }
     766      /* Files present here:
     767           {BASE}file
     768           {BASE}file2 -> {BASE}nowhere
     769           {BASE}link1 -> {BASE}file
     770           {BASE}dir/
     771       */
     772      ASSERT (unlink (BASE "file2") == 0);
     773    }
     774    /* Files present here:
     775         {BASE}file
     776         {BASE}link1 -> {BASE}file
     777         {BASE}dir/
     778     */
     779    { /* Trailing slash.  */
     780      {
     781        errno = 0;
     782        ASSERT (func (BASE "file/", BASE "link1") == -1);
     783        ASSERT (errno == ENOTDIR);
     784      }
     785      {
     786        errno = 0;
     787        ASSERT (func (BASE "file", BASE "link1/") == -1);
     788        ASSERT (errno == ENOTDIR || errno == ENOENT);
     789      }
     790      {
     791        errno = 0;
     792        ASSERT (func (BASE "link1/", BASE "file") == -1);
     793        ASSERT (errno == ENOTDIR);
     794      }
     795      {
     796        errno = 0;
     797        ASSERT (func (BASE "link1", BASE "file/") == -1);
     798        ASSERT (errno == ENOTDIR || errno == ENOENT);
     799        memset (&st, 0, sizeof st);
     800        ASSERT (lstat (BASE "file", &st) == 0);
     801        ASSERT (S_ISREG (st.st_mode));
     802        memset (&st, 0, sizeof st);
     803        ASSERT (lstat (BASE "link1", &st) == 0);
     804        ASSERT (S_ISLNK (st.st_mode));
     805      }
     806    }
     807    /* Files present here:
     808         {BASE}file
     809         {BASE}link1 -> {BASE}file
     810         {BASE}dir/
     811     */
     812  
     813    /* Mixing symlink and directory.  */
     814  
     815    { /* Directory onto link.  */
     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        errno = 0;
     828        ASSERT (func (BASE "dir", BASE "link1/") == -1);
     829        ASSERT (errno == ENOTDIR);
     830      }
     831    }
     832    { /* Link onto directory.  */
     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 == EISDIR || errno == ENOTDIR);
     842      }
     843      {
     844        errno = 0;
     845        ASSERT (func (BASE "link1/", BASE "dir") == -1);
     846        ASSERT (errno == ENOTDIR);
     847        memset (&st, 0, sizeof st);
     848        ASSERT (lstat (BASE "link1", &st) == 0);
     849        ASSERT (S_ISLNK (st.st_mode));
     850        memset (&st, 0, sizeof st);
     851        ASSERT (lstat (BASE "dir", &st) == 0);
     852        ASSERT (S_ISDIR (st.st_mode));
     853      }
     854    }
     855    /* Files present here:
     856         {BASE}file
     857         {BASE}link1 -> {BASE}file
     858         {BASE}dir/
     859     */
     860  
     861    /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
     862       leave "link-to-dir" dangling, but GNU rejects this.  POSIX
     863       requires rename("dir","dangling/") to create the directory so
     864       that "dangling/" now resolves, but GNU rejects this.  While we
     865       prefer GNU behavior, we don't enforce it.  However, we do test
     866       that the system either follows POSIX in both cases, or follows
     867       GNU.  */
     868    {
     869      int result;
     870      ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
     871      /* Files present here:
     872           {BASE}file
     873           {BASE}link1 -> {BASE}file
     874           {BASE}link2 -> {BASE}dir2
     875           {BASE}dir/
     876       */
     877      errno = 0;
     878      result = func (BASE "dir", BASE "link2/");
     879      if (result == 0)
     880        {
     881          /* POSIX.  */
     882          errno = 0;
     883          ASSERT (lstat (BASE "dir", &st) == -1);
     884          ASSERT (errno == ENOENT);
     885          memset (&st, 0, sizeof st);
     886          ASSERT (lstat (BASE "dir2", &st) == 0);
     887          ASSERT (S_ISDIR (st.st_mode));
     888          memset (&st, 0, sizeof st);
     889          ASSERT (lstat (BASE "link2", &st) == 0);
     890          ASSERT (S_ISLNK (st.st_mode));
     891          /* Files present here:
     892               {BASE}file
     893               {BASE}link1 -> {BASE}file
     894               {BASE}link2 -> {BASE}dir2
     895               {BASE}dir2/
     896           */
     897          {
     898            ASSERT (func (BASE "link2/", BASE "dir") == 0);
     899            memset (&st, 0, sizeof st);
     900            ASSERT (lstat (BASE "dir", &st) == 0);
     901            ASSERT (S_ISDIR (st.st_mode));
     902            errno = 0;
     903            ASSERT (lstat (BASE "dir2", &st) == -1);
     904            ASSERT (errno == ENOENT);
     905            memset (&st, 0, sizeof st);
     906            ASSERT (lstat (BASE "link2", &st) == 0);
     907            ASSERT (S_ISLNK (st.st_mode));
     908          }
     909        }
     910      else
     911        {
     912          /* GNU.  */
     913          ASSERT (result == -1);
     914          ASSERT (errno == ENOTDIR);
     915          memset (&st, 0, sizeof st);
     916          ASSERT (lstat (BASE "dir", &st) == 0);
     917          ASSERT (S_ISDIR (st.st_mode));
     918          errno = 0;
     919          ASSERT (lstat (BASE "dir2", &st) == -1);
     920          ASSERT (errno == ENOENT);
     921          memset (&st, 0, sizeof st);
     922          ASSERT (lstat (BASE "link2", &st) == 0);
     923          ASSERT (S_ISLNK (st.st_mode));
     924          ASSERT (unlink (BASE "link2") == 0);
     925          ASSERT (symlink (BASE "dir", BASE "link2") == 0);
     926          /* Files present here:
     927               {BASE}file
     928               {BASE}link1 -> {BASE}file
     929               {BASE}link2 -> {BASE}dir
     930               {BASE}dir/
     931           */
     932          errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
     933          result = func (BASE "link2/", BASE "dir");
     934          if (result) /* GNU/Linux rejects attempts to use link2/.  */
     935            {
     936              ASSERT (result == -1);
     937              ASSERT (errno == ENOTDIR || errno == EISDIR);
     938            }
     939          memset (&st, 0, sizeof st);
     940          ASSERT (lstat (BASE "dir", &st) == 0);
     941          ASSERT (S_ISDIR (st.st_mode));
     942          errno = 0;
     943          ASSERT (lstat (BASE "dir2", &st) == -1);
     944          ASSERT (errno == ENOENT);
     945          memset (&st, 0, sizeof st);
     946          ASSERT (lstat (BASE "link2", &st) == 0);
     947          ASSERT (S_ISLNK (st.st_mode));
     948        }
     949    }
     950    /* Files present here:
     951         {BASE}file
     952         {BASE}link1 -> {BASE}file
     953         {BASE}link2 -> {BASE}dir or {BASE}dir2
     954         {BASE}dir/
     955     */
     956  
     957    /* Clean up.  */
     958    ASSERT (unlink (BASE "file") == 0);
     959    ASSERT (rmdir (BASE "dir") == 0);
     960    ASSERT (unlink (BASE "link1") == 0);
     961    ASSERT (unlink (BASE "link2") == 0);
     962  
     963    return 0;
     964  }