packaging: Bump to version 1.4.17
[platform/upstream/m4.git] / tests / test-link.h
1 /* Test of link() function.
2    Copyright (C) 2009-2013 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 /* This file is designed to test both link(a,b) and
18    linkat(AT_FDCWD,a,AT_FDCWD,b,0).  FUNC is the function to test.
19    Assumes that BASE and ASSERT are already defined, and that
20    appropriate headers are already included.  If PRINT, warn before
21    skipping tests with status 77.  This test does not try to create
22    hard links to symlinks, but does test other aspects of symlink.  */
23
24 static int
25 test_link (int (*func) (char const *, char const *), bool print)
26 {
27   int fd;
28   int ret;
29
30   /* Create first file.  */
31   fd = open (BASE "a", O_CREAT | O_EXCL | O_WRONLY, 0600);
32   ASSERT (0 <= fd);
33   ASSERT (write (fd, "hello", 5) == 5);
34   ASSERT (close (fd) == 0);
35
36   /* Not all file systems support link.  Mingw doesn't have reliable
37      st_nlink on hard links, but our implementation does fail with
38      EPERM on poor file systems, and we can detect the inferior stat()
39      via st_ino.  Cygwin 1.5.x copies rather than links files on those
40      file systems, but there, st_nlink and st_ino are reliable.  */
41   ret = func (BASE "a", BASE "b");
42   if (!ret)
43   {
44     struct stat st;
45     ASSERT (stat (BASE "b", &st) == 0);
46     if (st.st_ino && st.st_nlink != 2)
47       {
48         ASSERT (unlink (BASE "b") == 0);
49         errno = EPERM;
50         ret = -1;
51       }
52   }
53   if (ret == -1)
54     {
55       /* If the device does not support hard links, errno is
56          EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
57       switch (errno)
58         {
59         case EPERM:
60         case EOPNOTSUPP:
61           if (print)
62             fputs ("skipping test: "
63                    "hard links not supported on this file system\n",
64                    stderr);
65           ASSERT (unlink (BASE "a") == 0);
66           return 77;
67         default:
68           perror ("link");
69           return 1;
70         }
71     }
72   ASSERT (ret == 0);
73
74   /* Now, for some behavior tests.  Modify the contents of 'b', and
75      ensure that 'a' can see it, both while 'b' exists and after.  */
76   fd = open (BASE "b", O_APPEND | O_WRONLY);
77   ASSERT (0 <= fd);
78   ASSERT (write (fd, "world", 5) == 5);
79   ASSERT (close (fd) == 0);
80   {
81     char buf[11] = { 0 };
82     fd = open (BASE "a", O_RDONLY);
83     ASSERT (0 <= fd);
84     ASSERT (read (fd, buf, 10) == 10);
85     ASSERT (strcmp (buf, "helloworld") == 0);
86     ASSERT (close (fd) == 0);
87     ASSERT (unlink (BASE "b") == 0);
88     fd = open (BASE "a", O_RDONLY);
89     ASSERT (0 <= fd);
90     ASSERT (read (fd, buf, 10) == 10);
91     ASSERT (strcmp (buf, "helloworld") == 0);
92     ASSERT (close (fd) == 0);
93   }
94
95   /* Test for various error conditions.  */
96   ASSERT (mkdir (BASE "d", 0700) == 0);
97   errno = 0;
98   ASSERT (func (BASE "a", ".") == -1);
99   ASSERT (errno == EEXIST || errno == EINVAL);
100   errno = 0;
101   ASSERT (func (BASE "a", BASE "a") == -1);
102   ASSERT (errno == EEXIST);
103   ASSERT (func (BASE "a", BASE "b") == 0);
104   errno = 0;
105   ASSERT (func (BASE "a", BASE "b") == -1);
106   ASSERT (errno == EEXIST);
107   errno = 0;
108   ASSERT (func (BASE "a", BASE "d") == -1);
109   ASSERT (errno == EEXIST);
110   errno = 0;
111   ASSERT (func (BASE "c", BASE "e") == -1);
112   ASSERT (errno == ENOENT);
113   errno = 0;
114   ASSERT (func (BASE "a", BASE "c/.") == -1);
115   ASSERT (errno == ENOENT);
116   errno = 0;
117   ASSERT (func (BASE "a/", BASE "c") == -1);
118   ASSERT (errno == ENOTDIR || errno == EINVAL);
119   errno = 0;
120   ASSERT (func (BASE "a", BASE "c/") == -1);
121   ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EINVAL);
122
123   /* Most platforms reject hard links to directories, and even on
124      those that do permit it, most users can't create them.  We assume
125      that if this test is run as root and we managed to create a hard
126      link, then unlink better be able to clean it up.  */
127   {
128     int result;
129     errno = 0;
130     result = func (BASE "d", BASE "c");
131     if (result == 0)
132       {
133         /* Probably root on Solaris.  */
134         ASSERT (unlink (BASE "c") == 0);
135       }
136     else
137       {
138         /* Most everyone else.  */
139         ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR);
140         errno = 0;
141         ASSERT (func (BASE "d/.", BASE "c") == -1);
142         ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
143                 || errno == EINVAL);
144         errno = 0;
145         ASSERT (func (BASE "d/.//", BASE "c") == -1);
146         ASSERT (errno == EPERM || errno == EACCES || errno == EISDIR
147                 || errno == EINVAL);
148       }
149   }
150   ASSERT (unlink (BASE "a") == 0);
151   errno = 0;
152   ASSERT (unlink (BASE "c") == -1);
153   ASSERT (errno == ENOENT);
154   ASSERT (rmdir (BASE "d") == 0);
155
156   /* Test invalid use of symlink.  */
157   if (symlink (BASE "a", BASE "link") != 0)
158     {
159       ASSERT (unlink (BASE "b") == 0);
160       if (print)
161         fputs ("skipping test: symlinks not supported on this file system\n",
162                stderr);
163       return 77;
164     }
165   errno = 0;
166   ASSERT (func (BASE "b", BASE "link/") == -1);
167   ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EEXIST
168           || errno == EINVAL);
169   errno = 0;
170   ASSERT (func (BASE "b", BASE "link") == -1);
171   ASSERT (errno == EEXIST);
172   ASSERT (rename (BASE "b", BASE "a") == 0);
173   errno = 0;
174   ASSERT (func (BASE "link/", BASE "b") == -1);
175   ASSERT (errno == ENOTDIR || errno == EEXIST || errno == EINVAL);
176
177   /* Clean up.  */
178   ASSERT (unlink (BASE "a") == 0);
179   ASSERT (unlink (BASE "link") == 0);
180
181   return 0;
182 }