linkat: new module
[gnulib.git] / tests / test-link.h
1 /* Test of link() function.
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 2 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 #include <config.h>
18
19 /* This file is designed to test both link(a,b) and
20    linkat(AT_FDCWD,a,AT_FDCWD,b).  FUNC is the function to test.
21    Assumes that BASE and ASSERT are already defined, and that
22    appropriate headers are already included.  If PRINT, warn before
23    skipping symlink tests with status 77.  */
24
25 static int
26 test_link (int (*func) (char const *, char const *), bool print)
27 {
28   int fd;
29   int ret;
30
31   /* Create first file.  */
32   fd = open (BASE "a", O_CREAT | O_EXCL | O_WRONLY, 0600);
33   ASSERT (0 <= fd);
34   ASSERT (write (fd, "hello", 5) == 5);
35   ASSERT (close (fd) == 0);
36
37   /* Not all file systems support link.  Mingw doesn't have reliable
38      st_nlink on hard links, but our implementation does fail with
39      EPERM on poor file systems, and we can detect the inferior stat()
40      via st_ino.  Cygwin 1.5.x copies rather than links files on those
41      file systems, but there, st_nlink and st_ino are reliable.  */
42   ret = func (BASE "a", BASE "b");
43   if (!ret)
44   {
45     struct stat st;
46     ASSERT (stat (BASE "b", &st) == 0);
47     if (st.st_ino && st.st_nlink != 2)
48       {
49         ASSERT (unlink (BASE "b") == 0);
50         errno = EPERM;
51         ret = -1;
52       }
53   }
54   if (ret == -1)
55     {
56       /* If the device does not support hard links, errno is
57          EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
58       switch (errno)
59         {
60         case EPERM:
61         case EOPNOTSUPP:
62           if (print)
63             fputs ("skipping test: "
64                    "hard links not supported on this file system\n",
65                    stderr);
66           ASSERT (unlink (BASE "a") == 0);
67           return 77;
68         default:
69           perror ("link");
70           return 1;
71         }
72     }
73   ASSERT (ret == 0);
74
75   /* Now, for some behavior tests.  Modify the contents of 'b', and
76      ensure that 'a' can see it, both while 'b' exists and after.  */
77   fd = open (BASE "b", O_APPEND | O_WRONLY);
78   ASSERT (0 <= fd);
79   ASSERT (write (fd, "world", 5) == 5);
80   ASSERT (close (fd) == 0);
81   {
82     char buf[11] = { 0 };
83     fd = open (BASE "a", O_RDONLY);
84     ASSERT (0 <= fd);
85     ASSERT (read (fd, buf, 10) == 10);
86     ASSERT (strcmp (buf, "helloworld") == 0);
87     ASSERT (close (fd) == 0);
88     ASSERT (unlink (BASE "b") == 0);
89     fd = open (BASE "a", O_RDONLY);
90     ASSERT (0 <= fd);
91     ASSERT (read (fd, buf, 10) == 10);
92     ASSERT (strcmp (buf, "helloworld") == 0);
93     ASSERT (close (fd) == 0);
94   }
95
96   /* Test for various error conditions.  Assumes hard links to
97      directories are not permitted.  */
98   ASSERT (mkdir (BASE "d", 0700) == 0);
99   errno = 0;
100   ASSERT (func (BASE "a", ".") == -1);
101   ASSERT (errno == EEXIST || errno == EINVAL);
102   errno = 0;
103   ASSERT (func (BASE "a", BASE "a") == -1);
104   ASSERT (errno == EEXIST);
105   ASSERT (func (BASE "a", BASE "b") == 0);
106   errno = 0;
107   ASSERT (func (BASE "a", BASE "b") == -1);
108   ASSERT (errno == EEXIST);
109   errno = 0;
110   ASSERT (func (BASE "a", BASE "d") == -1);
111   ASSERT (errno == EEXIST);
112   errno = 0;
113   ASSERT (func (BASE "c", BASE "e") == -1);
114   ASSERT (errno == ENOENT);
115   errno = 0;
116   ASSERT (func (BASE "a", BASE "c/.") == -1);
117   ASSERT (errno == ENOENT);
118   errno = 0;
119   ASSERT (func (BASE "a/", BASE "c") == -1);
120   ASSERT (errno == ENOTDIR);
121   errno = 0;
122   ASSERT (func (BASE "a", BASE "c/") == -1);
123   ASSERT (errno == ENOTDIR || errno == ENOENT);
124   errno = 0;
125   ASSERT (func (BASE "d", BASE "c") == -1);
126   ASSERT (errno == EPERM || errno == EACCES);
127
128   /* Clean up.  */
129   ASSERT (unlink (BASE "a") == 0);
130   ASSERT (unlink (BASE "b") == 0);
131   errno = 0;
132   ASSERT (unlink (BASE "c") == -1);
133   ASSERT (errno == ENOENT);
134   ASSERT (rmdir (BASE "d") == 0);
135
136   return 0;
137 }