Back to index

glibc  2.9
test-canon.c
Go to the documentation of this file.
00001 /* Test program for returning the canonical absolute name of a given file.
00002    Copyright (C) 1996,1997,2000,2002,2004,2005,2006
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by David Mosberger <davidm@azstarnet.com>.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 /* This file must be run from within a directory called "stdlib".  */
00023 
00024 #include <errno.h>
00025 #include <fcntl.h>
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <sys/param.h>
00031 
00032 /* Prototype for our test function.  */
00033 extern int do_test (int argc, char *argv[]);
00034 #include <test-skeleton.c>
00035 
00036 #ifndef PATH_MAX
00037 # define PATH_MAX 4096
00038 #endif
00039 static char   cwd[PATH_MAX];
00040 static size_t cwd_len;
00041 
00042 struct {
00043   const char *       name;
00044   const char *       value;
00045 } symlinks[] = {
00046   {"SYMLINK_LOOP",   "SYMLINK_LOOP"},
00047   {"SYMLINK_1",             "."},
00048   {"SYMLINK_2",             "//////./../../etc"},
00049   {"SYMLINK_3",             "SYMLINK_1"},
00050   {"SYMLINK_4",             "SYMLINK_2"},
00051   {"SYMLINK_5",             "doesNotExist"},
00052 };
00053 
00054 struct {
00055   const char * in, * out, * resolved;
00056   int error;
00057 } tests[] = {
00058   /*  0 */
00059   {"/",                                   "/"},
00060   {"/////////////////////////////////",   "/"},
00061   {"/.././.././.././..///",        "/"},
00062   {"/etc",                         "/etc"},
00063   {"/etc/../etc",                  "/etc"},
00064   /*  5 */
00065   {"/doesNotExist/../etc",         0, "/doesNotExist", ENOENT},
00066   {"./././././././././.",          "."},
00067   {"/etc/.//doesNotExist",         0, "/etc/doesNotExist", ENOENT},
00068   {"./doesExist",                  "./doesExist"},
00069   {"./doesExist/",                 "./doesExist"},
00070   /* 10 */
00071   {"./doesExist/../doesExist",            "./doesExist"},
00072   {"foobar",                       0, "./foobar", ENOENT},
00073   {".",                                   "."},
00074   {"./foobar",                            0, "./foobar", ENOENT},
00075   {"SYMLINK_LOOP",                 0, "./SYMLINK_LOOP", ELOOP},
00076   /* 15 */
00077   {"./SYMLINK_LOOP",               0, "./SYMLINK_LOOP", ELOOP},
00078   {"SYMLINK_1",                           "."},
00079   {"SYMLINK_1/foobar",                    0, "./foobar", ENOENT},
00080   {"SYMLINK_2",                           "/etc"},
00081   {"SYMLINK_3",                           "."},
00082   /* 20 */
00083   {"SYMLINK_4",                           "/etc"},
00084   {"../stdlib/SYMLINK_1",          "."},
00085   {"../stdlib/SYMLINK_2",          "/etc"},
00086   {"../stdlib/SYMLINK_3",          "."},
00087   {"../stdlib/SYMLINK_4",          "/etc"},
00088   /* 25 */
00089   {"./SYMLINK_5",                  0, "./doesNotExist", ENOENT},
00090   {"SYMLINK_5",                           0, "./doesNotExist", ENOENT},
00091   {"SYMLINK_5/foobar",                    0, "./doesNotExist", ENOENT},
00092   {"doesExist/../../stdlib/doesExist",    "./doesExist"},
00093   {"doesExist/.././../stdlib/.",   "."},
00094   /* 30 */
00095   {"./doesExist/someFile/",        0, "./doesExist/someFile", ENOTDIR},
00096   {"./doesExist/someFile/..",             0, "./doesExist/someFile", ENOTDIR},
00097 };
00098 
00099 
00100 static int
00101 check_path (const char * result, const char * expected)
00102 {
00103   int good;
00104 
00105   if (!result)
00106     return (expected == NULL);
00107 
00108   if (!expected)
00109     return 0;
00110 
00111   if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0'))
00112     good = (strncmp (result, cwd, cwd_len) == 0
00113            && strcmp (result + cwd_len, expected + 1) == 0);
00114   else
00115     good = (strcmp (expected, result) == 0);
00116 
00117   return good;
00118 }
00119 
00120 
00121 int
00122 do_test (int argc, char ** argv)
00123 {
00124   char * result;
00125   int i, errors = 0;
00126   char buf[PATH_MAX];
00127 
00128   getcwd (cwd, sizeof(buf));
00129   cwd_len = strlen (cwd);
00130 
00131   errno = 0;
00132   if (realpath (NULL, buf) != NULL || errno != EINVAL)
00133     {
00134       printf ("%s: expected return value NULL and errno set to EINVAL"
00135              " for realpath(NULL,...)\n", argv[0]);
00136       ++errors;
00137     }
00138 
00139 #if 0
00140   /* This is now allowed.  The test is invalid.  */
00141   errno = 0;
00142   if (realpath ("/", NULL) != NULL || errno != EINVAL)
00143     {
00144       printf ("%s: expected return value NULL and errno set to EINVAL"
00145              " for realpath(...,NULL)\n", argv[0]);
00146       ++errors;
00147     }
00148 #endif
00149 
00150   errno = 0;
00151   if (realpath ("", buf) != NULL || errno != ENOENT)
00152     {
00153       printf ("%s: expected return value NULL and set errno to ENOENT"
00154              " for realpath(\"\",...)\n", argv[0]);
00155       ++errors;
00156     }
00157 
00158   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
00159     symlink (symlinks[i].value, symlinks[i].name);
00160 
00161   int has_dir = mkdir ("doesExist", 0777) == 0;
00162 
00163   int fd = has_dir ? creat ("doesExist/someFile", 0777) : -1;
00164 
00165   for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i)
00166     {
00167       buf[0] = '\0';
00168       result = realpath (tests[i].in, buf);
00169 
00170       if (!check_path (result, tests[i].out))
00171        {
00172          printf ("%s: flunked test %d (expected `%s', got `%s')\n",
00173                 argv[0], i, tests[i].out ? tests[i].out : "NULL",
00174                 result ? result : "NULL");
00175          ++errors;
00176          continue;
00177        }
00178 
00179       if (!check_path (buf, tests[i].out ? tests[i].out : tests[i].resolved))
00180        {
00181          printf ("%s: flunked test %d (expected resolved `%s', got `%s')\n",
00182                 argv[0], i, tests[i].out ? tests[i].out : tests[i].resolved,
00183                 buf);
00184          ++errors;
00185          continue;
00186        }
00187 
00188       if (!tests[i].out && errno != tests[i].error)
00189        {
00190          printf ("%s: flunked test %d (expected errno %d, got %d)\n",
00191                 argv[0], i, tests[i].error, errno);
00192          ++errors;
00193          continue;
00194        }
00195 
00196       char *result2 = realpath (tests[i].in, NULL);
00197       if ((result2 == NULL && result != NULL)
00198          || (result2 != NULL && strcmp (result, result2) != 0))
00199        {
00200          printf ("\
00201 %s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n",
00202                 argv[0], result2, result);
00203          ++errors;
00204        }
00205       free (result2);
00206     }
00207 
00208   getcwd (buf, sizeof(buf));
00209   if (strcmp (buf, cwd))
00210     {
00211       printf ("%s: current working directory changed from %s to %s\n",
00212              argv[0], cwd, buf);
00213       ++errors;
00214     }
00215 
00216   if (fd >= 0)
00217     {
00218       close (fd);
00219       unlink ("doesExist/someFile");
00220     }
00221 
00222   if (has_dir)
00223     rmdir ("doesExist");
00224 
00225   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
00226     unlink (symlinks[i].name);
00227 
00228   if (errors != 0)
00229     {
00230       printf ("%d errors.\n", errors);
00231       return EXIT_FAILURE;
00232     }
00233 
00234   puts ("No errors.");
00235   return EXIT_SUCCESS;
00236 }