(root)/
m4-1.4.19/
tests/
test-link.h
       1  /* Test of link() 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 link(a,b) and
      18     linkat(AT_FDCWD,a,AT_FDCWD,b,0).  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 tests with status 77.  This test does not try to create
      22     hard links to symlinks, but does test other aspects of symlink.  */
      23  
      24  static int
      25  test_link (int (*func) (char const *, char const *), bool print)
      26  {
      27    int fd;
      28    int ret;
      29  
      30    /* Create first file.  */
      31    fd = open (BASE "a", O_CREAT | O_EXCL | O_WRONLY, 0600);
      32    ASSERT (0 <= fd);
      33    ASSERT (write (fd, "hello", 5) == 5);
      34    ASSERT (close (fd) == 0);
      35  
      36    /* Not all file systems support link.  Mingw doesn't have reliable
      37       st_nlink on hard links, but our implementation does fail with
      38       EPERM on poor file systems, and we can detect the inferior stat()
      39       via st_ino.  Cygwin 1.5.x copies rather than links files on those
      40       file systems, but there, st_nlink and st_ino are reliable.  */
      41    ret = func (BASE "a", BASE "b");
      42    if (!ret)
      43    {
      44      struct stat st;
      45      ASSERT (stat (BASE "b", &st) == 0);
      46      if (st.st_ino && st.st_nlink != 2)
      47        {
      48          ASSERT (unlink (BASE "b") == 0);
      49          errno = EPERM;
      50          ret = -1;
      51        }
      52    }
      53    if (ret == -1)
      54      {
      55        /* If the device does not support hard links, errno is
      56           EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
      57        switch (errno)
      58          {
      59          case EPERM:
      60          case EOPNOTSUPP:
      61            if (print)
      62              fputs ("skipping test: "
      63                     "hard links not supported on this file system\n",
      64                     stderr);
      65            ASSERT (unlink (BASE "a") == 0);
      66            return 77;
      67          default:
      68            perror ("link");
      69            return 1;
      70          }
      71      }
      72    ASSERT (ret == 0);
      73  
      74    /* Now, for some behavior tests.  Modify the contents of 'b', and
      75       ensure that 'a' can see it, both while 'b' exists and after.  */
      76    fd = open (BASE "b", O_APPEND | O_WRONLY);
      77    ASSERT (0 <= fd);
      78    ASSERT (write (fd, "world", 5) == 5);
      79    ASSERT (close (fd) == 0);
      80    {
      81      char buf[11] = { 0 };
      82      fd = open (BASE "a", O_RDONLY);
      83      ASSERT (0 <= fd);
      84      ASSERT (read (fd, buf, 10) == 10);
      85      ASSERT (strcmp (buf, "helloworld") == 0);
      86      ASSERT (close (fd) == 0);
      87      ASSERT (unlink (BASE "b") == 0);
      88      fd = open (BASE "a", O_RDONLY);
      89      ASSERT (0 <= fd);
      90      ASSERT (read (fd, buf, 10) == 10);
      91      ASSERT (strcmp (buf, "helloworld") == 0);
      92      ASSERT (close (fd) == 0);
      93    }
      94  
      95    /* Test for various error conditions.  */
      96    ASSERT (mkdir (BASE "d", 0700) == 0);
      97    errno = 0;
      98    ASSERT (func (BASE "a", ".") == -1);
      99    ASSERT (errno == EEXIST || errno == EINVAL);
     100    errno = 0;
     101    ASSERT (func (BASE "a", BASE "a") == -1);
     102    ASSERT (errno == EEXIST);
     103    ASSERT (func (BASE "a", BASE "b") == 0);
     104    errno = 0;
     105    ASSERT (func (BASE "a", BASE "b") == -1);
     106    ASSERT (errno == EEXIST);
     107    errno = 0;
     108    ASSERT (func (BASE "a", BASE "d") == -1);
     109    ASSERT (errno == EEXIST);
     110    errno = 0;
     111    ASSERT (func (BASE "c", BASE "e") == -1);
     112    ASSERT (errno == ENOENT);
     113    errno = 0;
     114    ASSERT (func (BASE "a", BASE "c/.") == -1);
     115    ASSERT (errno == ENOENT);
     116    errno = 0;
     117    ASSERT (func (BASE "a/", BASE "c") == -1);
     118    ASSERT (errno == ENOTDIR || errno == EINVAL);
     119    errno = 0;
     120    ASSERT (func (BASE "a", BASE "c/") == -1);
     121    ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EINVAL);
     122  
     123    /* Most platforms reject hard links to directories, and even on
     124       those that do permit it, most users can't create them.  We assume
     125       that if this test is run as root and we managed to create a hard
     126       link, then unlink better be able to clean it up.  */
     127    {
     128      int result;
     129      errno = 0;
     130      result = func (BASE "d", BASE "c");
     131      if (result == 0)
     132        {
     133          /* Probably root on Solaris.  */
     134          ASSERT (unlink (BASE "c") == 0);
     135        }
     136      else
     137        {
     138          /* Most everyone else.  */
     139          ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR);
     140          errno = 0;
     141          ASSERT (func (BASE "d/.", BASE "c") == -1);
     142          ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
     143                  || errno == EINVAL);
     144          errno = 0;
     145          ASSERT (func (BASE "d/.//", BASE "c") == -1);
     146          ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
     147                  || errno == EINVAL);
     148        }
     149    }
     150    ASSERT (unlink (BASE "a") == 0);
     151    errno = 0;
     152    ASSERT (unlink (BASE "c") == -1);
     153    ASSERT (errno == ENOENT);
     154    ASSERT (rmdir (BASE "d") == 0);
     155  
     156    /* Test invalid use of symlink.  */
     157    if (symlink (BASE "a", BASE "link") != 0)
     158      {
     159        ASSERT (unlink (BASE "b") == 0);
     160        if (print)
     161          fputs ("skipping test: symlinks not supported on this file system\n",
     162                 stderr);
     163        return 77;
     164      }
     165    errno = 0;
     166    ASSERT (func (BASE "b", BASE "link/") == -1);
     167    ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EEXIST
     168            || errno == EINVAL);
     169    errno = 0;
     170    ASSERT (func (BASE "b", BASE "link") == -1);
     171    ASSERT (errno == EEXIST);
     172    ASSERT (rename (BASE "b", BASE "a") == 0);
     173    errno = 0;
     174    ASSERT (func (BASE "link/", BASE "b") == -1);
     175    ASSERT (errno == ENOTDIR || errno == EEXIST || errno == EINVAL);
     176  
     177    /* Clean up.  */
     178    ASSERT (unlink (BASE "a") == 0);
     179    ASSERT (unlink (BASE "link") == 0);
     180  
     181    return 0;
     182  }