(root)/
glibc-2.38/
stdlib/
test-canon.c
       1  /* Test program for returning the canonical absolute name of a given file.
       2     Copyright (C) 1996-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  /* This file must be run from within a directory called "stdlib".  */
      20  
      21  #include <errno.h>
      22  #include <fcntl.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <unistd.h>
      27  #include <sys/param.h>
      28  #include <sys/stat.h>
      29  
      30  #include <support/xunistd.h>
      31  
      32  /* Prototype for our test function.  */
      33  extern int do_test (int argc, char *argv[]);
      34  #include <test-skeleton.c>
      35  
      36  #ifndef PATH_MAX
      37  # define PATH_MAX 4096
      38  #endif
      39  static char	cwd[PATH_MAX];
      40  static size_t	cwd_len;
      41  
      42  struct {
      43    const char *	name;
      44    const char *	value;
      45  } symlinks[] = {
      46    {"SYMLINK_LOOP",	"SYMLINK_LOOP"},
      47    {"SYMLINK_1",		"."},
      48    {"SYMLINK_2",		"//////./../../etc"},
      49    {"SYMLINK_3",		"SYMLINK_1"},
      50    {"SYMLINK_4",		"SYMLINK_2"},
      51    {"SYMLINK_5",		"doesNotExist"},
      52  };
      53  
      54  struct {
      55    const char * in, * out, * resolved;
      56    int error;
      57  } tests[] = {
      58    /*  0 */
      59    {"/",					"/"},
      60    {"/////////////////////////////////",	"/"},
      61    {"/.././.././.././..///",		"/"},
      62    {"/etc",				"/etc"},
      63    {"/etc/../etc",			"/etc"},
      64    /*  5 */
      65    {"/doesNotExist/../etc",		0, "/doesNotExist", ENOENT},
      66    {"./././././././././.",		"."},
      67    {"/etc/.//doesNotExist",		0, "/etc/doesNotExist", ENOENT},
      68    {"./doesExist",			"./doesExist"},
      69    {"./doesExist/",			"./doesExist"},
      70    /* 10 */
      71    {"./doesExist/../doesExist",		"./doesExist"},
      72    {"foobar",				0, "./foobar", ENOENT},
      73    {".",					"."},
      74    {"./foobar",				0, "./foobar", ENOENT},
      75    {"SYMLINK_LOOP",			0, "./SYMLINK_LOOP", ELOOP},
      76    /* 15 */
      77    {"./SYMLINK_LOOP",			0, "./SYMLINK_LOOP", ELOOP},
      78    {"SYMLINK_1",				"."},
      79    {"SYMLINK_1/foobar",			0, "./foobar", ENOENT},
      80    {"SYMLINK_2",				"/etc"},
      81    {"SYMLINK_3",				"."},
      82    /* 20 */
      83    {"SYMLINK_4",				"/etc"},
      84    {"../stdlib/SYMLINK_1",		"."},
      85    {"../stdlib/SYMLINK_2",		"/etc"},
      86    {"../stdlib/SYMLINK_3",		"."},
      87    {"../stdlib/SYMLINK_4",		"/etc"},
      88    /* 25 */
      89    {"./SYMLINK_5",			0, "./doesNotExist", ENOENT},
      90    {"SYMLINK_5",				0, "./doesNotExist", ENOENT},
      91    {"SYMLINK_5/foobar",			0, "./doesNotExist", ENOENT},
      92    {"doesExist/../../stdlib/doesExist",	"./doesExist"},
      93    {"doesExist/.././../stdlib/.",	"."},
      94    /* 30 */
      95    {"./doesExist/someFile/",		0, "./doesExist/someFile", ENOTDIR},
      96    {"./doesExist/someFile/..",		0, "./doesExist/someFile", ENOTDIR},
      97  };
      98  
      99  
     100  static int
     101  check_path (const char * result, const char * expected)
     102  {
     103    int good;
     104  
     105    if (!result)
     106      return (expected == NULL);
     107  
     108    if (!expected)
     109      return 0;
     110  
     111    if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0'))
     112      good = (strncmp (result, cwd, cwd_len) == 0
     113  	    && strcmp (result + cwd_len, expected + 1) == 0);
     114    else
     115      good = (strcmp (expected, result) == 0);
     116  
     117    return good;
     118  }
     119  
     120  
     121  int
     122  do_test (int argc, char ** argv)
     123  {
     124    char * result;
     125    int i, errors = 0;
     126    char buf[PATH_MAX];
     127  
     128    if (getcwd (cwd, sizeof (buf)))
     129      cwd_len = strlen (cwd);
     130    else
     131      {
     132        printf ("%s: current working directory couldn't be retrieved\n", argv[0]);
     133        ++errors;
     134      }
     135  
     136    errno = 0;
     137    if (realpath (NULL, buf) != NULL || errno != EINVAL)
     138      {
     139        printf ("%s: expected return value NULL and errno set to EINVAL"
     140  	      " for realpath(NULL,...)\n", argv[0]);
     141        ++errors;
     142      }
     143  
     144  #if 0
     145    /* This is now allowed.  The test is invalid.  */
     146    errno = 0;
     147    if (realpath ("/", NULL) != NULL || errno != EINVAL)
     148      {
     149        printf ("%s: expected return value NULL and errno set to EINVAL"
     150  	      " for realpath(...,NULL)\n", argv[0]);
     151        ++errors;
     152      }
     153  #endif
     154  
     155    errno = 0;
     156    if (realpath ("", buf) != NULL || errno != ENOENT)
     157      {
     158        printf ("%s: expected return value NULL and set errno to ENOENT"
     159  	      " for realpath(\"\",...)\n", argv[0]);
     160        ++errors;
     161      }
     162  
     163    for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
     164      xsymlink (symlinks[i].value, symlinks[i].name);
     165  
     166    int has_dir = mkdir ("doesExist", 0777) == 0;
     167  
     168    int fd = has_dir ? creat ("doesExist/someFile", 0777) : -1;
     169  
     170    for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i)
     171      {
     172        buf[0] = '\0';
     173        result = realpath (tests[i].in, buf);
     174  
     175        if (!check_path (result, tests[i].out))
     176  	{
     177  	  printf ("%s: flunked test %d (expected `%s', got `%s')\n",
     178  		  argv[0], i, tests[i].out ? tests[i].out : "NULL",
     179  		  result ? result : "NULL");
     180  	  ++errors;
     181  	  continue;
     182  	}
     183  
     184        /* Verify buf contents if the call succeeded or failed with ENOENT.  */
     185        if ((result != NULL || errno == ENOENT)
     186  	  && !check_path (buf, tests[i].out ? tests[i].out : tests[i].resolved))
     187  	{
     188  	  printf ("%s: flunked test %d (expected resolved `%s', got `%s')\n",
     189  		  argv[0], i, tests[i].out ? tests[i].out : tests[i].resolved,
     190  		  buf);
     191  	  ++errors;
     192  	  continue;
     193  	}
     194  
     195        if (!tests[i].out && errno != tests[i].error)
     196  	{
     197  	  printf ("%s: flunked test %d (expected errno %d, got %d)\n",
     198  		  argv[0], i, tests[i].error, errno);
     199  	  ++errors;
     200  	  continue;
     201  	}
     202  
     203        char *result2 = realpath (tests[i].in, NULL);
     204        if ((result2 == NULL && result != NULL)
     205  	  || (result2 != NULL && strcmp (result, result2) != 0))
     206  	{
     207  	  printf ("\
     208  %s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n",
     209  		  argv[0], result2, result);
     210  	  ++errors;
     211  	}
     212        free (result2);
     213      }
     214  
     215    if (!getcwd (buf, sizeof (buf)))
     216      {
     217        printf ("%s: current working directory couldn't be retrieved\n", argv[0]);
     218        ++errors;
     219      }
     220  
     221    if (strcmp (buf, cwd))
     222      {
     223        printf ("%s: current working directory changed from %s to %s\n",
     224  	      argv[0], cwd, buf);
     225        ++errors;
     226      }
     227  
     228    if (fd >= 0)
     229      {
     230        close (fd);
     231        unlink ("doesExist/someFile");
     232      }
     233  
     234    if (has_dir)
     235      rmdir ("doesExist");
     236  
     237    for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
     238      unlink (symlinks[i].name);
     239  
     240    if (errors != 0)
     241      {
     242        printf ("%d errors.\n", errors);
     243        return EXIT_FAILURE;
     244      }
     245  
     246    puts ("No errors.");
     247    return EXIT_SUCCESS;
     248  }