rename-tests: new test, exposes several platform bugs
[gnulib.git] / tests / test-rename.h
1 /* Test of rename() 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 /* This file is designed to test both rename(a,b) and
18    renameat(AT_FDCWD,a,AT_FDCWD,b).  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 symlink tests with status 77.  */
22
23 static int
24 test_rename (int (*func) (char const *, char const *), bool print)
25 {
26   /* Setup.  */
27   struct stat st;
28   int fd = creat (BASE "file", 0600);
29   ASSERT (0 <= fd);
30   ASSERT (write (fd, "hi", 2) == 2);
31   ASSERT (close (fd) == 0);
32   ASSERT (mkdir (BASE "dir", 0700) == 0);
33
34   /* Obvious errors.  */
35
36   errno = 0; /* Missing source.  */
37   ASSERT (func (BASE "missing", BASE "missing") == -1);
38   ASSERT (errno == ENOENT);
39   errno = 0;
40   ASSERT (func (BASE "missing/", BASE "missing") == -1);
41   ASSERT (errno == ENOENT);
42   errno = 0;
43   ASSERT (func (BASE "missing", BASE "missing/") == -1);
44   ASSERT (errno == ENOENT);
45   errno = 0; /* Empty operand.  */
46   ASSERT (func ("", BASE "missing") == -1);
47   ASSERT (errno == ENOENT);
48   errno = 0;
49   ASSERT (func (BASE "file", "") == -1);
50   ASSERT (errno == ENOENT);
51   errno = 0;
52   ASSERT (func (BASE "", "") == -1);
53   ASSERT (errno == ENOENT);
54
55   /* Files.  */
56   errno = 0; /* Trailing slash.  */
57   ASSERT (func (BASE "file", BASE "file2/") == -1);
58   ASSERT (errno == ENOENT || errno == ENOTDIR);
59   errno = 0;
60   ASSERT (func (BASE "file/", BASE "file2") == -1);
61   ASSERT (errno == ENOTDIR);
62   errno = 0;
63   ASSERT (stat (BASE "file2", &st) == -1);
64   ASSERT (errno == ENOENT);
65   ASSERT (func (BASE "file", BASE "file2") == 0); /* Simple rename.  */
66   errno = 0;
67   ASSERT (stat (BASE "file", &st) == -1);
68   ASSERT (errno == ENOENT);
69   memset (&st, 0, sizeof st);
70   ASSERT (stat (BASE "file2", &st) == 0);
71   ASSERT (st.st_size == 2);
72   ASSERT (close (creat (BASE "file", 0600)) == 0); /* Overwrite.  */
73   errno = 0;
74   ASSERT (func (BASE "file2", BASE "file/") == -1);
75   ASSERT (errno == ENOTDIR);
76   ASSERT (func (BASE "file2", BASE "file") == 0);
77   memset (&st, 0, sizeof st);
78   ASSERT (stat (BASE "file", &st) == 0);
79   ASSERT (st.st_size == 2);
80   errno = 0;
81   ASSERT (stat (BASE "file2", &st) == -1);
82   ASSERT (errno == ENOENT);
83
84   /* Directories.  */
85   ASSERT (func (BASE "dir", BASE "dir2/") == 0); /* Simple rename.  */
86   errno = 0;
87   ASSERT (stat (BASE "dir", &st) == -1);
88   ASSERT (errno == ENOENT);
89   ASSERT (stat (BASE "dir2", &st) == 0);
90   ASSERT (func (BASE "dir2/", BASE "dir") == 0);
91   ASSERT (stat (BASE "dir", &st) == 0);
92   errno = 0;
93   ASSERT (stat (BASE "dir2", &st) == -1);
94   ASSERT (errno == ENOENT);
95   ASSERT (func (BASE "dir", BASE "dir2") == 0);
96   errno = 0;
97   ASSERT (stat (BASE "dir", &st) == -1);
98   ASSERT (errno == ENOENT);
99   ASSERT (stat (BASE "dir2", &st) == 0);
100   ASSERT (mkdir (BASE "dir", 0700) == 0); /* Empty onto empty.  */
101   ASSERT (func (BASE "dir2", BASE "dir") == 0);
102   ASSERT (mkdir (BASE "dir2", 0700) == 0);
103   ASSERT (func (BASE "dir2", BASE "dir/") == 0);
104   ASSERT (mkdir (BASE "dir2", 0700) == 0);
105   ASSERT (func (BASE "dir2/", BASE "dir") == 0);
106   ASSERT (mkdir (BASE "dir2", 0700) == 0);
107   ASSERT (close (creat (BASE "dir/file", 0600)) == 0); /* Empty onto full.  */
108   errno = 0;
109   ASSERT (func (BASE "dir2", BASE "dir") == -1);
110   ASSERT (errno == EEXIST || errno == ENOTEMPTY);
111   errno = 0;
112   ASSERT (func (BASE "dir2/", BASE "dir") == -1);
113   ASSERT (errno == EEXIST || errno == ENOTEMPTY);
114   errno = 0;
115   ASSERT (func (BASE "dir2", BASE "dir/") == -1);
116   ASSERT (errno == EEXIST || errno == ENOTEMPTY);
117   ASSERT (func (BASE "dir", BASE "dir2") == 0); /* Full onto empty.  */
118   errno = 0;
119   ASSERT (stat (BASE "dir", &st) == -1);
120   ASSERT (errno == ENOENT);
121   ASSERT (stat (BASE "dir2/file", &st) == 0);
122   ASSERT (mkdir (BASE "dir", 0700) == 0);
123   ASSERT (func (BASE "dir2/", BASE "dir") == 0);
124   ASSERT (stat (BASE "dir/file", &st) == 0);
125   errno = 0;
126   ASSERT (stat (BASE "dir2", &st) == -1);
127   ASSERT (errno == ENOENT);
128   ASSERT (mkdir (BASE "dir2", 0700) == 0);
129   ASSERT (func (BASE "dir", BASE "dir2/") == 0);
130   errno = 0;
131   ASSERT (stat (BASE "dir", &st) == -1);
132   ASSERT (errno == ENOENT);
133   ASSERT (stat (BASE "dir2/file", &st) == 0);
134   ASSERT (unlink (BASE "dir2/file") == 0);
135   errno = 0; /* Reject trailing dot.  */
136   ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
137   ASSERT (errno == EINVAL || errno == ENOENT);
138   ASSERT (mkdir (BASE "dir", 0700) == 0);
139   errno = 0;
140   ASSERT (func (BASE "dir2", BASE "dir/.") == -1);
141   ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR);
142   errno = 0;
143   ASSERT (func (BASE "dir2/.", BASE "dir") == -1);
144   ASSERT (errno == EINVAL || errno == EBUSY);
145   ASSERT (rmdir (BASE "dir") == 0);
146   errno = 0;
147   ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
148   ASSERT (errno == EINVAL || errno == ENOENT);
149   ASSERT (mkdir (BASE "dir", 0700) == 0);
150   errno = 0;
151   ASSERT (func (BASE "dir2", BASE "dir/.//") == -1);
152   ASSERT (errno == EINVAL || errno == EBUSY || errno == EISDIR);
153   errno = 0;
154   ASSERT (func (BASE "dir2/.//", BASE "dir") == -1);
155   ASSERT (errno == EINVAL || errno == EBUSY);
156   ASSERT (rmdir (BASE "dir2") == 0);
157   errno = 0; /* Move into subdir.  */
158   ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
159   ASSERT (errno == EINVAL || errno == EACCES);
160   errno = 0;
161   ASSERT (stat (BASE "dir/sub", &st) == -1);
162   ASSERT (errno == ENOENT);
163   ASSERT (mkdir (BASE "dir/sub", 0700) == 0);
164   errno = 0;
165   ASSERT (func (BASE "dir", BASE "dir/sub") == -1);
166   ASSERT (errno == EINVAL);
167   ASSERT (stat (BASE "dir/sub", &st) == 0);
168   ASSERT (rmdir (BASE "dir/sub") == 0);
169
170   /* Mixing file and directory.  */
171   errno = 0; /* File onto dir.  */
172   ASSERT (func (BASE "file", BASE "dir") == -1);
173   ASSERT (errno == EISDIR || errno == ENOTDIR);
174   errno = 0;
175   ASSERT (func (BASE "file", BASE "dir/") == -1);
176   ASSERT (errno == EISDIR || errno == ENOTDIR);
177   errno = 0; /* Dir onto file.  */
178   ASSERT (func (BASE "dir", BASE "file") == -1);
179   ASSERT (errno == ENOTDIR);
180   errno = 0;
181   ASSERT (func (BASE "dir/", BASE "file") == -1);
182   ASSERT (errno == ENOTDIR);
183
184   /* Hard links.  */
185   ASSERT (func (BASE "file", BASE "file") == 0); /* File onto self.  */
186   memset (&st, 0, sizeof st);
187   ASSERT (stat (BASE "file", &st) == 0);
188   ASSERT (st.st_size == 2);
189   ASSERT (func (BASE "dir", BASE "dir") == 0); /* Empty dir onto self.  */
190   ASSERT (stat (BASE "dir", &st) == 0);
191   ASSERT (close (creat (BASE "dir/file", 0600)) == 0);
192   ASSERT (func (BASE "dir", BASE "dir") == 0); /* Full dir onto self.  */
193   ASSERT (unlink (BASE "dir/file") == 0);
194   {
195     /*  Not all file systems support link.  Mingw doesn't have
196         reliable st_nlink on hard links, but our implementation does
197         fail with EPERM on poor file systems, and we can detect the
198         inferior stat() via st_ino.  Cygwin 1.5.x copies rather than
199         links files on those file systems, but there, st_nlink and
200         st_ino are reliable.  */
201     int ret = link (BASE "file", BASE "file2");
202     if (!ret)
203       {
204         memset (&st, 0, sizeof st);
205         ASSERT (stat (BASE "file2", &st) == 0);
206         if (st.st_ino && st.st_nlink != 2)
207           {
208             ASSERT (unlink (BASE "file2") == 0);
209             errno = EPERM;
210             ret = -1;
211           }
212       }
213     if (ret == -1)
214       {
215         /* If the device does not support hard links, errno is
216            EPERM on Linux, EOPNOTSUPP on FreeBSD.  */
217         switch (errno)
218           {
219           case EPERM:
220           case EOPNOTSUPP:
221             if (print)
222               fputs ("skipping test: "
223                      "hard links not supported on this file system\n",
224                      stderr);
225             ASSERT (unlink (BASE "file") == 0);
226             ASSERT (rmdir (BASE "dir") == 0);
227             return 77;
228           default:
229             perror ("link");
230             return 1;
231           }
232       }
233     ASSERT (ret == 0);
234   }
235   ASSERT (func (BASE "file", BASE "file2") == 0); /* File onto hard link.  */
236   memset (&st, 0, sizeof st);
237   ASSERT (stat (BASE "file", &st) == 0);
238   ASSERT (st.st_size == 2);
239   memset (&st, 0, sizeof st);
240   ASSERT (stat (BASE "file2", &st) == 0);
241   ASSERT (st.st_size == 2);
242   ASSERT (unlink (BASE "file2") == 0);
243
244   /* Symlinks.  */
245   if (symlink (BASE "file", BASE "link1"))
246     {
247       if (print)
248         fputs ("skipping test: symlinks not supported on this filesystem\n",
249                stderr);
250       ASSERT (unlink (BASE "file") == 0);
251       ASSERT (rmdir (BASE "dir") == 0);
252       return 77;
253     }
254   ASSERT (func (BASE "link1", BASE "link2") == 0); /* Simple rename.  */
255   ASSERT (stat (BASE "file", &st) == 0);
256   errno = 0;
257   ASSERT (lstat (BASE "link1", &st) == -1);
258   ASSERT (errno == ENOENT);
259   memset (&st, 0, sizeof st);
260   ASSERT (lstat (BASE "link2", &st) == 0);
261   ASSERT (S_ISLNK (st.st_mode));
262   ASSERT (symlink (BASE "nowhere", BASE "link1") == 0); /* Overwrite.  */
263   ASSERT (func (BASE "link2", BASE "link1") == 0);
264   memset (&st, 0, sizeof st);
265   ASSERT (stat (BASE "link1", &st) == 0);
266   ASSERT (st.st_size == 2);
267   errno = 0;
268   ASSERT (lstat (BASE "link2", &st) == -1);
269   ASSERT (errno == ENOENT);
270   ASSERT (symlink (BASE "link2", BASE "link2") == 0); /* Symlink loop.  */
271   ASSERT (func (BASE "link2", BASE "link2") == 0);
272   errno = 0;
273   ASSERT (func (BASE "link2/", BASE "link2") == -1);
274   ASSERT (errno == ELOOP || errno == ENOTDIR);
275   ASSERT (func (BASE "link2", BASE "link3") == 0);
276   ASSERT (unlink (BASE "link3") == 0);
277   ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Dangling link.  */
278   ASSERT (func (BASE "link2", BASE "link3") == 0);
279   errno = 0;
280   ASSERT (lstat (BASE "link2", &st) == -1);
281   ASSERT (errno == ENOENT);
282   memset (&st, 0, sizeof st);
283   ASSERT (lstat (BASE "link3", &st) == 0);
284   errno = 0; /* Trailing slash on dangling.  */
285   ASSERT (func (BASE "link3/", BASE "link2") == -1);
286   ASSERT (errno == ENOENT || errno == ENOTDIR);
287   errno = 0;
288   ASSERT (func (BASE "link3", BASE "link2/") == -1);
289   ASSERT (errno == ENOENT || errno == ENOTDIR);
290   errno = 0;
291   ASSERT (lstat (BASE "link2", &st) == -1);
292   ASSERT (errno == ENOENT);
293   memset (&st, 0, sizeof st);
294   ASSERT (lstat (BASE "link3", &st) == 0);
295   errno = 0; /* Trailing slash on link to file.  */
296   ASSERT (func (BASE "link1/", BASE "link2") == -1);
297   ASSERT (errno == ENOTDIR);
298   errno = 0;
299   ASSERT (func (BASE "link1", BASE "link3/") == -1);
300   ASSERT (errno == ENOENT || errno == ENOTDIR);
301
302   /* Mixing symlink and file.  */
303   ASSERT (close (creat (BASE "file2", 0600)) == 0); /* File onto link.  */
304   ASSERT (func (BASE "file2", BASE "link3") == 0);
305   errno = 0;
306   ASSERT (stat (BASE "file2", &st) == -1);
307   ASSERT (errno == ENOENT);
308   memset (&st, 0, sizeof st);
309   ASSERT (lstat (BASE "link3", &st) == 0);
310   ASSERT (S_ISREG (st.st_mode));
311   ASSERT (unlink (BASE "link3") == 0);
312   ASSERT (symlink (BASE "nowhere", BASE "link2") == 0); /* Link onto file.  */
313   ASSERT (close (creat (BASE "file2", 0600)) == 0);
314   ASSERT (func (BASE "link2", BASE "file2") == 0);
315   errno = 0;
316   ASSERT (lstat (BASE "link2", &st) == -1);
317   ASSERT (errno == ENOENT);
318   memset (&st, 0, sizeof st);
319   ASSERT (lstat (BASE "file2", &st) == 0);
320   ASSERT (S_ISLNK (st.st_mode));
321   ASSERT (unlink (BASE "file2") == 0);
322   errno = 0; /* Trailing slash.  */
323   ASSERT (func (BASE "file/", BASE "link1") == -1);
324   ASSERT (errno == ENOTDIR);
325   errno = 0;
326   ASSERT (func (BASE "file", BASE "link1/") == -1);
327   ASSERT (errno == ENOTDIR || errno == ENOENT);
328   errno = 0;
329   ASSERT (func (BASE "link1/", BASE "file") == -1);
330   ASSERT (errno == ENOTDIR);
331   errno = 0;
332   ASSERT (func (BASE "link1", BASE "file/") == -1);
333   ASSERT (errno == ENOTDIR || errno == ENOENT);
334   memset (&st, 0, sizeof st);
335   ASSERT (lstat (BASE "file", &st) == 0);
336   ASSERT (S_ISREG (st.st_mode));
337   memset (&st, 0, sizeof st);
338   ASSERT (lstat (BASE "link1", &st) == 0);
339   ASSERT (S_ISLNK (st.st_mode));
340
341   /* Mixing symlink and directory.  */
342   errno = 0; /* Directory onto link.  */
343   ASSERT (func (BASE "dir", BASE "link1") == -1);
344   ASSERT (errno == ENOTDIR);
345   errno = 0;
346   ASSERT (func (BASE "dir/", BASE "link1") == -1);
347   ASSERT (errno == ENOTDIR);
348   errno = 0;
349   ASSERT (func (BASE "dir", BASE "link1/") == -1);
350   ASSERT (errno == ENOTDIR);
351   errno = 0; /* Link onto directory.  */
352   ASSERT (func (BASE "link1", BASE "dir") == -1);
353   ASSERT (errno == EISDIR || errno == ENOTDIR);
354   errno = 0;
355   ASSERT (func (BASE "link1", BASE "dir/") == -1);
356   ASSERT (errno == EISDIR || errno == ENOTDIR);
357   errno = 0;
358   ASSERT (func (BASE "link1/", BASE "dir") == -1);
359   ASSERT (errno == ENOTDIR);
360   memset (&st, 0, sizeof st);
361   ASSERT (lstat (BASE "link1", &st) == 0);
362   ASSERT (S_ISLNK (st.st_mode));
363   memset (&st, 0, sizeof st);
364   ASSERT (lstat (BASE "dir", &st) == 0);
365   ASSERT (S_ISDIR (st.st_mode));
366
367   /* POSIX requires rename("link-to-dir/","other") to rename "dir" and
368      leave "link-to-dir" dangling, but GNU rejects this.  POSIX
369      requires rename("dir","dangling/") to create the directory so
370      that "dangling/" now resolves, but GNU rejects this.  While we
371      prefer GNU behavior, we don't enforce it.  However, we do test
372      that the system either follows POSIX in both cases, or follows
373      GNU.  */
374   {
375     int result;
376     ASSERT (symlink (BASE "dir2", BASE "link2") == 0);
377     errno = 0;
378     result = func (BASE "dir", BASE "link2/");
379     if (result == 0)
380       {
381         /* POSIX.  */
382         errno = 0;
383         ASSERT (lstat (BASE "dir", &st) == -1);
384         ASSERT (errno == ENOENT);
385         memset (&st, 0, sizeof st);
386         ASSERT (lstat (BASE "dir2", &st) == 0);
387         ASSERT (S_ISDIR (st.st_mode));
388         memset (&st, 0, sizeof st);
389         ASSERT (lstat (BASE "link2", &st) == 0);
390         ASSERT (S_ISLNK (st.st_mode));
391         ASSERT (func (BASE "link2/", BASE "dir") == 0);
392         memset (&st, 0, sizeof st);
393         ASSERT (lstat (BASE "dir", &st) == 0);
394         ASSERT (S_ISDIR (st.st_mode));
395         errno = 0;
396         ASSERT (lstat (BASE "dir2", &st) == -1);
397         ASSERT (errno == ENOENT);
398         memset (&st, 0, sizeof st);
399         ASSERT (lstat (BASE "link2", &st) == 0);
400         ASSERT (S_ISLNK (st.st_mode));
401       }
402     else
403       {
404         /* GNU.  */
405         ASSERT (result == -1);
406         ASSERT (errno == ENOTDIR);
407         memset (&st, 0, sizeof st);
408         ASSERT (lstat (BASE "dir", &st) == 0);
409         ASSERT (S_ISDIR (st.st_mode));
410         errno = 0;
411         ASSERT (lstat (BASE "dir2", &st) == -1);
412         ASSERT (errno == ENOENT);
413         memset (&st, 0, sizeof st);
414         ASSERT (lstat (BASE "link2", &st) == 0);
415         ASSERT (S_ISLNK (st.st_mode));
416         ASSERT (unlink (BASE "link2") == 0);
417         ASSERT (symlink (BASE "dir", BASE "link2") == 0);
418         errno = 0; /* OpenBSD notices that link2/ and dir are the same.  */
419         result = func (BASE "link2/", BASE "dir");
420         if (result) /* GNU/Linux rejects attempts to use link2/.  */
421           {
422             ASSERT (result == -1);
423             ASSERT (errno == ENOTDIR);
424           }
425         memset (&st, 0, sizeof st);
426         ASSERT (lstat (BASE "dir", &st) == 0);
427         ASSERT (S_ISDIR (st.st_mode));
428         errno = 0;
429         ASSERT (lstat (BASE "dir2", &st) == -1);
430         ASSERT (errno == ENOENT);
431         memset (&st, 0, sizeof st);
432         ASSERT (lstat (BASE "link2", &st) == 0);
433         ASSERT (S_ISLNK (st.st_mode));
434       }
435   }
436
437   /* Clean up.  */
438   ASSERT (unlink (BASE "file") == 0);
439   ASSERT (rmdir (BASE "dir") == 0);
440   ASSERT (unlink (BASE "link1") == 0);
441   ASSERT (unlink (BASE "link2") == 0);
442
443   return 0;
444 }