(root)/
glibc-2.38/
posix/
tst-glob_symlinks.c
       1  /* Test glob danglin symlink match (BZ #866).
       2     Copyright (C) 2017-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdio.h>
      20  #include <string.h>
      21  #include <stdlib.h>
      22  #include <errno.h>
      23  #include <unistd.h>
      24  #include <limits.h>
      25  #include <stddef.h>
      26  #include <glob.h>
      27  #include <sys/stat.h>
      28  #include <sys/types.h>
      29  
      30  #include <support/check.h>
      31  #include <support/temp_file.h>
      32  
      33  static void do_prepare (int argc, char *argv[]);
      34  #define PREPARE do_prepare
      35  static int do_test (void);
      36  #include <support/test-driver.c>
      37  
      38  /* Maximum number of symlink calls for create_link function.  */
      39  #define MAX_CREATE_LINK_TRIES 10
      40  
      41  static void
      42  create_link (const char *base, const char *fname, char *linkname,
      43  	     size_t linknamesize)
      44  {
      45    int ntries = 0;
      46    while (1)
      47      {
      48        snprintf (linkname, linknamesize, "%s/%s%02d", test_dir, base,
      49  		ntries);
      50        if (symlink (fname, linkname) == 0)
      51  	break;
      52        if (errno != EEXIST)
      53  	FAIL_EXIT1 ("symlink failed: %m");
      54        if (ntries++ == MAX_CREATE_LINK_TRIES)
      55  	FAIL_EXIT1 ("symlink failed with EEXIST too many times");
      56      }
      57    add_temp_file (linkname);
      58  }
      59  
      60  #ifndef PATH_MAX
      61  # define PATH_MAX 1024
      62  #endif
      63  static char valid_link[PATH_MAX];
      64  static char dangling_link[PATH_MAX];
      65  static char dangling_dir[PATH_MAX];
      66  
      67  static void
      68  do_prepare (int argc, char *argv[])
      69  {
      70    char *fname;
      71  
      72    create_temp_file ("tst-glob_symlinks.", &fname);
      73  
      74    /* Create an existing symlink.  */
      75    create_link ("valid-symlink-tst-glob_symlinks", fname, valid_link,
      76  	       sizeof valid_link);
      77  
      78    /* Create a dangling symlink to a file.  */
      79    int fd = create_temp_file ("dangling-tst-glob_file", &fname);
      80    TEST_VERIFY_EXIT (close (fd) == 0);
      81    /* It throws a warning at process end due 'add_temp_file' trying to
      82       unlink it again.  */
      83    TEST_VERIFY_EXIT (unlink (fname) == 0);
      84    create_link ("dangling-symlink-file-tst-glob", fname, dangling_link,
      85  	       sizeof dangling_link);
      86  
      87    /* Create a dangling symlink to a directory.  */
      88    char tmpdir[PATH_MAX];
      89    snprintf (tmpdir, sizeof tmpdir, "%s/dangling-tst-glob_folder.XXXXXX",
      90  	    test_dir);
      91    TEST_VERIFY_EXIT (mkdtemp (tmpdir) != NULL);
      92    create_link ("dangling-symlink-dir-tst-glob", tmpdir, dangling_dir,
      93  	       sizeof dangling_dir);
      94    TEST_VERIFY_EXIT (rmdir (tmpdir) == 0);
      95  }
      96  
      97  static int
      98  do_test (void)
      99  {
     100    char buf[PATH_MAX + 1];
     101    glob_t gl;
     102  
     103    TEST_VERIFY_EXIT (glob (valid_link, 0, NULL, &gl) == 0);
     104    TEST_VERIFY_EXIT (gl.gl_pathc == 1);
     105    TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], valid_link) == 0);
     106    globfree (&gl);
     107  
     108    TEST_VERIFY_EXIT (glob (dangling_link, 0, NULL, &gl) == 0);
     109    TEST_VERIFY_EXIT (gl.gl_pathc == 1);
     110    TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
     111    globfree (&gl);
     112  
     113    TEST_VERIFY_EXIT (glob (dangling_dir, 0, NULL, &gl) == 0);
     114    TEST_VERIFY_EXIT (gl.gl_pathc == 1);
     115    TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_dir) == 0);
     116    globfree (&gl);
     117  
     118    snprintf (buf, sizeof buf, "%s", dangling_link);
     119    buf[strlen(buf) - 1] = '?';
     120    TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
     121    TEST_VERIFY_EXIT (gl.gl_pathc == 1);
     122    TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
     123    globfree (&gl);
     124  
     125    /* glob should handle dangling symbol as normal file, so <file>? should
     126       return an empty string.  */
     127    snprintf (buf, sizeof buf, "%s?", dangling_link);
     128    TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) != 0);
     129    globfree (&gl);
     130  
     131    snprintf (buf, sizeof buf, "%s*", dangling_link);
     132    TEST_VERIFY_EXIT (glob (buf, 0, NULL, &gl) == 0);
     133    TEST_VERIFY_EXIT (gl.gl_pathc == 1);
     134    TEST_VERIFY_EXIT (strcmp (gl.gl_pathv[0], dangling_link) == 0);
     135    globfree (&gl);
     136  
     137    return 0;
     138  }