readlink: fix Solaris 9 bug with trailing slash
[pspp] / tests / test-readlink.c
1 /* Tests of readlink.
2    Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
18
19 #include <config.h>
20
21 #include <unistd.h>
22
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29
30 #define ASSERT(expr) \
31   do                                                                         \
32     {                                                                        \
33       if (!(expr))                                                           \
34         {                                                                    \
35           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
36           fflush (stderr);                                                   \
37           abort ();                                                          \
38         }                                                                    \
39     }                                                                        \
40   while (0)
41
42 #define BASE "test-readlink.t"
43
44 int
45 main ()
46 {
47   char buf[80];
48
49   /* Remove any leftovers from a previous partial run.  */
50   ASSERT (system ("rm -rf " BASE "*") == 0);
51
52   /* Sanity checks of failures.  Mingw lacks symlink, but readlink can
53      still distinguish between various errors.  */
54   memset (buf, 0xff, sizeof buf);
55   errno = 0;
56   ASSERT (readlink ("no_such", buf, sizeof buf) == -1);
57   ASSERT (errno == ENOENT);
58   errno = 0;
59   ASSERT (readlink ("no_such/", buf, sizeof buf) == -1);
60   ASSERT (errno == ENOENT);
61   errno = 0;
62   ASSERT (readlink ("", buf, sizeof buf) == -1);
63   ASSERT (errno == ENOENT);
64   errno = 0;
65   ASSERT (readlink (".", buf, sizeof buf) == -1);
66   ASSERT (errno == EINVAL);
67   errno = 0;
68   ASSERT (readlink ("./", buf, sizeof buf) == -1);
69   ASSERT (errno == EINVAL);
70   ASSERT (close (creat (BASE "file", 0600)) == 0);
71   errno = 0;
72   ASSERT (readlink (BASE "file", buf, sizeof buf) == -1);
73   ASSERT (errno == EINVAL);
74   errno = 0;
75   ASSERT (readlink (BASE "file/", buf, sizeof buf) == -1);
76   ASSERT (errno == ENOTDIR);
77   ASSERT (unlink (BASE "file") == 0);
78
79   /* Now test actual symlinks.  */
80   if (symlink (BASE "dir", BASE "link"))
81     {
82       fputs ("skipping test: symlinks not supported on this filesystem\n",
83              stderr);
84       return 77;
85     }
86   ASSERT (mkdir (BASE "dir", 0700) == 0);
87   errno = 0;
88   ASSERT (readlink (BASE "link/", buf, sizeof buf) == -1);
89   ASSERT (errno == EINVAL);
90   {
91     /* Up till now, no readlink has been successful, so buf should be
92        unchanged.  */
93     int i;
94     for (i = 0; i < sizeof buf; i++)
95       ASSERT (buf[i] == (char) 0xff);
96   }
97   {
98     size_t len = strlen (BASE "dir");
99     /* When passing too small of a buffer, expect the truncated
100        length.  However, a size of 0 is not portable enough to
101        test.  */
102     ASSERT (readlink (BASE "link", buf, 1) == 1);
103     ASSERT (buf[0] == BASE[0]);
104     ASSERT (buf[1] == (char) 0xff);
105     ASSERT (readlink (BASE "link", buf, len) == len);
106     ASSERT (strncmp (buf, BASE "dir", len) == 0);
107     ASSERT (buf[len] == (char) 0xff);
108     ASSERT (readlink (BASE "link", buf, sizeof buf) == len);
109     ASSERT (strncmp (buf, BASE "dir", len) == 0);
110     /* POSIX says rest of buf is unspecified; but in practice, it is
111        either left alone, or NUL-terminated.  */
112     ASSERT (buf[len] == '\0' || buf[len] == (char) 0xff);
113   }
114   ASSERT (rmdir (BASE "dir") == 0);
115   ASSERT (unlink (BASE "link") == 0);
116
117   return 0;
118 }