(root)/
grep-3.11/
gnulib-tests/
test-open.h
       1  /* Test of opening a file descriptor.
       2     Copyright (C) 2007-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  /* Written by Bruno Haible <bruno@clisp.org>, 2007.  */
      18  
      19  /* Tell GCC not to warn about the specific edge cases tested here.  */
      20  #if __GNUC__ >= 13
      21  # pragma GCC diagnostic ignored "-Wanalyzer-fd-leak"
      22  #endif
      23  
      24  /* Make test_open always inline if we're using Fortify, which defines
      25     __always_inline to do that.  Do nothing otherwise.  This works
      26     around a glibc bug whereby 'open' cannot be used as a function
      27     pointer when _FORTIFY_SOURCE is positive.  */
      28  
      29  #if __GLIBC__ && defined __always_inline
      30  # define ALWAYS_INLINE __always_inline
      31  #else
      32  # define ALWAYS_INLINE
      33  #endif
      34  
      35  /* This file is designed to test both open(n,buf[,mode]) and
      36     openat(AT_FDCWD,n,buf[,mode]).  FUNC is the function to test.
      37     Assumes that BASE and ASSERT are already defined, and that
      38     appropriate headers are already included.  If PRINT, warn before
      39     skipping symlink tests with status 77.  */
      40  
      41  static ALWAYS_INLINE int
      42  test_open (int (*func) (char const *, int, ...), bool print)
      43  {
      44    int fd;
      45  
      46    /* Remove anything from prior partial run.  */
      47    unlink (BASE "file");
      48    unlink (BASE "e.exe");
      49    unlink (BASE "link");
      50  
      51    /* Cannot create directory.  */
      52    errno = 0;
      53    ASSERT (func ("nonexist.ent/", O_CREAT | O_RDONLY, 0600) == -1);
      54    ASSERT (errno == ENOTDIR || errno == EISDIR || errno == ENOENT
      55            || errno == EINVAL);
      56  
      57    /* Create a regular file.  */
      58    fd = func (BASE "file", O_CREAT | O_RDONLY, 0600);
      59    ASSERT (0 <= fd);
      60    ASSERT (close (fd) == 0);
      61  
      62    /* Create an executable regular file.  */
      63    fd = func (BASE "e.exe", O_CREAT | O_RDONLY, 0700);
      64    ASSERT (0 <= fd);
      65    ASSERT (close (fd) == 0);
      66  
      67    /* Trailing slash handling.  */
      68    errno = 0;
      69    ASSERT (func (BASE "file/", O_RDONLY) == -1);
      70    ASSERT (errno == ENOTDIR || errno == EISDIR || errno == EINVAL);
      71  
      72    /* Directories cannot be opened for writing.  */
      73    errno = 0;
      74    ASSERT (func (".", O_WRONLY) == -1);
      75    ASSERT (errno == EISDIR || errno == EACCES);
      76  
      77    /* /dev/null must exist, and be writable.  */
      78    fd = func ("/dev/null", O_RDONLY);
      79    ASSERT (0 <= fd);
      80    {
      81      char c;
      82      ASSERT (read (fd, &c, 1) == 0);
      83    }
      84    ASSERT (close (fd) == 0);
      85    fd = func ("/dev/null", O_WRONLY);
      86    ASSERT (0 <= fd);
      87    ASSERT (write (fd, "c", 1) == 1);
      88    ASSERT (close (fd) == 0);
      89  
      90    /* Although O_NONBLOCK on regular files can be ignored, it must not
      91       cause a failure.  */
      92    fd = func (BASE "file", O_NONBLOCK | O_RDONLY);
      93    ASSERT (0 <= fd);
      94    ASSERT (close (fd) == 0);
      95  
      96    /* O_CLOEXEC must be honoured.  */
      97    if (O_CLOEXEC)
      98      {
      99        /* Since the O_CLOEXEC handling goes through a special code path at its
     100           first invocation, test it twice.  */
     101        int i;
     102  
     103        for (i = 0; i < 2; i++)
     104          {
     105            int flags;
     106  
     107            fd = func (BASE "file", O_CLOEXEC | O_RDONLY);
     108            ASSERT (0 <= fd);
     109            flags = fcntl (fd, F_GETFD);
     110            ASSERT (flags >= 0);
     111            ASSERT ((flags & FD_CLOEXEC) != 0);
     112            ASSERT (close (fd) == 0);
     113          }
     114      }
     115  
     116    /* Symlink handling, where supported.  */
     117    if (symlink (BASE "file", BASE "link") != 0)
     118      {
     119        ASSERT (unlink (BASE "file") == 0);
     120        if (print)
     121          fputs ("skipping test: symlinks not supported on this file system\n",
     122                 stderr);
     123        return 77;
     124      }
     125    errno = 0;
     126    ASSERT (func (BASE "link/", O_RDONLY) == -1);
     127    ASSERT (errno == ENOTDIR);
     128    fd = func (BASE "link", O_RDONLY);
     129    ASSERT (0 <= fd);
     130    ASSERT (close (fd) == 0);
     131  
     132    /* Cleanup.  */
     133    ASSERT (unlink (BASE "file") == 0);
     134    ASSERT (unlink (BASE "e.exe") == 0);
     135    ASSERT (unlink (BASE "link") == 0);
     136  
     137    return 0;
     138  }